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 2019/09/29 22:18:30 UTC

[qpid-broker-j] branch 7.1.x updated (b0d5112 -> 001d9ea)

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 b0d5112  QPID-8356: [Broker-J] Fix loading of ACL rules containing firewall properties
     new c81cea7  QPID-8353: [Broker-J] Add TLSv1.3 into TLS protocol preferences
     new d3b0a88  QPID-8354: [Broker-J] Blacklist TLSv1.1
     new 6af6079  QPID-8354: [Broker-J] Address review comments from Oleksandr Rudyy
     new 21c101a  QPID-8360: [Broker-J]Add broker and virtual host loggers storing log records in database
     new 1129da1  QPID-8360: [Broker-J] Update licenseMerge for 'Eclipse Public License' to accept license specified as 'MPL 2.0 or EPL 1.0'
     new d2c0c65  QPID-8360: [Broker-J] Update depenecies reference file
     new cde6d07  QPID-8360: [Broker-J] Clean-up code
     new ae197f8  QPID-8360: [Broker-J] Change logger types to upper-case for consistency reasons
     new 097031e  QPID-8363: [Broker-J] Add support for GSSAPI authentication into SimpleLDAP authentication provider
     new a9aedc7  QPID-8364: [Broker-J] Add support for SPNEGO authentication
     new 88a37dc  QPID-8363: [Broker-J] Fix test dependency scope
     new 001d9ea  NO-JIRA: Exclude test dependecies from license check

The 12 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 |   2 +
 broker-core/pom.xml                                |  12 +
 .../server/configuration/CommonProperties.java     |   4 +-
 .../java/org/apache/qpid/server/model/Broker.java  |   6 +-
 ...urityToken.java => TokenCarryingPrincipal.java} |   8 +-
 .../manager/KerberosAuthenticationManager.java     |  82 +++-
 .../auth/manager/LdapAuthenticationMethod.java     |  23 +-
 .../manager/SimpleLDAPAuthenticationManager.java   |  20 +-
 .../SimpleLDAPAuthenticationManagerImpl.java       | 207 ++++++---
 .../security/auth/manager/SpnegoAuthenticator.java | 293 ++++++++++++
 .../transport/network/security/ssl/SSLUtil.java    |   6 +-
 .../manager/KerberosAuthenticationManagerTest.java | 262 +++++++++++
 .../SimpleLDAPAuthenticationManagerTest.java       | 495 +++++++++++++++++++++
 .../auth/manager/SpnegoAuthenticatorTest.java      | 175 ++++++++
 .../qpid/server/test/EmbeddedKdcResource.java      | 196 ++++++++
 .../apache/qpid/server/test/KerberosUtilities.java | 189 ++++++++
 .../server/transport/TCPandSSLTransportTest.java   | 207 ++++++---
 .../network/security/ssl/SSLUtilTest.java          |  10 +-
 broker-core/src/test/resources/login.config        |  80 ++++
 .../src/test/resources/users.ldif                  |  38 +-
 .../{derby-store => jdbc-logging-logback}/pom.xml  |  63 ++-
 .../logging/logback/jdbc/JDBCBrokerLogger.java}    |  31 +-
 .../logging/logback/jdbc/JDBCBrokerLoggerImpl.java | 171 +++++++
 .../logging/logback/jdbc/JDBCLoggerHelper.java     | 114 +++++
 .../logback/jdbc/JDBCSettingsDBNameResolver.java   |  42 +-
 .../jdbc/JDBCSettingsDrivenConnectionSource.java   | 111 +++++
 .../logback/jdbc/JDBCVirtualHostLogger.java}       |  27 +-
 .../logback/jdbc/JDBCVirtualHostLoggerImpl.java    | 137 ++++++
 .../management/logger/brokerlogger/jdbc}/add.js    |  30 +-
 .../management/logger/brokerlogger/jdbc}/show.js   |  46 +-
 .../logger/virtualhostlogger/jdbc}/add.js          |  30 +-
 .../logger/virtualhostlogger/jdbc}/show.js         |  47 +-
 .../src/main/java/resources/logger/jdbc/add.html   |  93 ++++
 .../src/main/java/resources/logger/jdbc}/show.html |  18 +-
 .../logback/jdbc/InMemoryDatabaseTestBase.java}    |  45 +-
 .../logback/jdbc/JDBCBrokerLoggerImplTest.java     | 149 +++++++
 .../logging/logback/jdbc/JDBCLoggerHelperTest.java | 114 +++++
 .../jdbc/JDBCSettingsDBNameResolverTest.java       |  60 +++
 .../JDBCSettingsDrivenConnectionSourceTest.java    | 104 +++++
 .../jdbc/JDBCVirtualHostLoggerImplTest.java        | 137 ++++++
 .../js/qpid/management/store/pool/bonecp/show.js   |   5 +-
 .../qpid/server/store/jdbc/JDBCSettings.java       |   6 +
 .../apache/qpid/server/store/jdbc/JdbcUtils.java   |  36 +-
 .../qpid/management/store/pool/ConnectionPool.js   | 113 +++++
 .../server/logging/logback/AbstractLogger.java     |   7 +-
 .../logging/logback/BrokerFileLoggerImpl.java      |  48 +-
 .../logback/BrokerLoggerStatusListener.java        |  83 ++++
 ...st.java => BrokerLoggerStatusListenerTest.java} |  16 +-
 .../server/management/plugin/HttpManagement.java   |   1 +
 .../auth/SpnegoInteractiveAuthenticator.java       | 102 +++++
 ...tor.java => SpnegoPreemptiveAuthenticator.java} |  39 +-
 .../plugin/filter/AuthenticationCheckFilter.java   |   4 +
 .../src/main/java/resources/addLogger.html         |   5 +
 .../authenticationprovider/simpleldap/add.html     |  30 +-
 .../authenticationprovider/simpleldap/show.html    |   8 +
 .../java/resources/js/qpid/management/addLogger.js |  27 +-
 .../authenticationprovider/simpleldap/add.js       |  36 +-
 .../authenticationprovider/simpleldap/show.js      |   7 +-
 broker/pom.xml                                     |   6 +
 ...-Security-Authentication-Providers-Kerberos.xml |  46 +-
 ...oker-Security-Authentication-Providers-LDAP.xml |  10 +
 pom.xml                                            |  38 +-
 .../qpid/test/utils/SystemPropertySetter.java      |  38 +-
 .../org/apache/qpid/test/utils/UnitTestBase.java   |  38 +-
 64 files changed, 4105 insertions(+), 528 deletions(-)
 copy broker-core/src/main/java/org/apache/qpid/server/security/{SecurityToken.java => TokenCarryingPrincipal.java} (87%)
 copy broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/codec/VariableWidthTypeConstructor.java => broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/LdapAuthenticationMethod.java (73%)
 create mode 100644 broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SpnegoAuthenticator.java
 create mode 100644 broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/KerberosAuthenticationManagerTest.java
 create mode 100644 broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerTest.java
 create mode 100644 broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SpnegoAuthenticatorTest.java
 create mode 100644 broker-core/src/test/java/org/apache/qpid/server/test/EmbeddedKdcResource.java
 create mode 100644 broker-core/src/test/java/org/apache/qpid/server/test/KerberosUtilities.java
 create mode 100644 broker-core/src/test/resources/login.config
 copy joramtests/src/test/resources/jms-client/jndi.properties => broker-core/src/test/resources/users.ldif (55%)
 copy broker-plugins/{derby-store => jdbc-logging-logback}/pom.xml (54%)
 copy broker-plugins/{jdbc-store/src/main/java/org/apache/qpid/server/virtualhost/jdbc/JDBCVirtualHost.java => jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLogger.java} (60%)
 create mode 100644 broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLoggerImpl.java
 create mode 100644 broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCLoggerHelper.java
 copy broker-core/src/main/java/org/apache/qpid/server/bytebuffer/NonPooledByteBufferRef.java => broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDBNameResolver.java (52%)
 create mode 100644 broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDrivenConnectionSource.java
 copy broker-plugins/{jdbc-store/src/main/java/org/apache/qpid/server/virtualhost/jdbc/JDBCVirtualHost.java => jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLogger.java} (57%)
 create mode 100644 broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLoggerImpl.java
 copy broker-plugins/{management-http/src/main/java/resources/js/qpid/management/groupprovider/groupfile => jdbc-logging-logback/src/main/java/resources/js/qpid/management/logger/brokerlogger/jdbc}/add.js (54%)
 copy broker-plugins/{logging-logback/src/main/java/resources/js/qpid/management/logger/brokerlogger/memory => jdbc-logging-logback/src/main/java/resources/js/qpid/management/logger/brokerlogger/jdbc}/show.js (50%)
 copy broker-plugins/{management-http/src/main/java/resources/js/qpid/management/groupprovider/groupfile => jdbc-logging-logback/src/main/java/resources/js/qpid/management/logger/virtualhostlogger/jdbc}/add.js (54%)
 copy broker-plugins/{logging-logback/src/main/java/resources/js/qpid/management/logger/brokerlogger/memory => jdbc-logging-logback/src/main/java/resources/js/qpid/management/logger/virtualhostlogger/jdbc}/show.js (50%)
 create mode 100644 broker-plugins/jdbc-logging-logback/src/main/java/resources/logger/jdbc/add.html
 copy broker-plugins/{management-http/src/main/java/resources/virtualhost/sizemonitoring => jdbc-logging-logback/src/main/java/resources/logger/jdbc}/show.html (64%)
 copy broker-plugins/{jdbc-store/src/main/java/org/apache/qpid/server/store/jdbc/DefaultConnectionProvider.java => jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/InMemoryDatabaseTestBase.java} (53%)
 create mode 100644 broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLoggerImplTest.java
 create mode 100644 broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCLoggerHelperTest.java
 create mode 100644 broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDBNameResolverTest.java
 create mode 100644 broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDrivenConnectionSourceTest.java
 create mode 100644 broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLoggerImplTest.java
 create mode 100644 broker-plugins/jdbc-store/src/main/java/resources/js/qpid/management/store/pool/ConnectionPool.js
 create mode 100644 broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/BrokerLoggerStatusListener.java
 rename broker-plugins/logging-logback/src/test/java/org/apache/qpid/server/logging/logback/{BrokerFileLoggerStatusListenerTest.java => BrokerLoggerStatusListenerTest.java} (87%)
 create mode 100644 broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/auth/SpnegoInteractiveAuthenticator.java
 copy broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/auth/{OAuth2PreemptiveAuthenticator.java => SpnegoPreemptiveAuthenticator.java} (58%)
 copy broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQTypeMap.java => qpid-test-utils/src/main/java/org/apache/qpid/test/utils/SystemPropertySetter.java (56%)


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


[qpid-broker-j] 06/12: QPID-8360: [Broker-J] Update depenecies reference file

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 d2c0c6530e5e95262e85738bd56c02dbf0eb5472
Author: Alex Rudyy <or...@apache.org>
AuthorDate: Mon Sep 9 11:09:00 2019 +0100

    QPID-8360: [Broker-J] Update depenecies reference file
    
    (cherry picked from commit 7ffbe9859e46a6ae8bbe39d1684f0f21e1954628)
---
 .../src/main/assembly/dependency-verification/DEPENDENCIES_REFERENCE    | 2 ++
 1 file changed, 2 insertions(+)

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 1cde70e..127ddd9 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
@@ -97,6 +97,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 Derby Message Store Plug-in (http://qpid.apache.org/components/broker-plugins/qpid-broker-plugins-derby-store) org.apache.qpid:qpid-broker-plugins-derby-store:jar
     License: Apache License, Version 2.0  (https://www.apache.org/licenses/LICENSE-2.0.txt)
+  - Apache Qpid Broker-J LogBack JDBC Logging Plug-in (http://qpid.apache.org/components/broker-plugins/qpid-broker-plugins-jdbc-logging-logback) org.apache.qpid:qpid-broker-plugins-jdbc-logging-logback:jar
+    License: Apache License, Version 2.0  (https://www.apache.org/licenses/LICENSE-2.0.txt)
   - Apache Qpid Broker-J JDBC Message Store Connection Pooling Plug-in (http://qpid.apache.org/components/broker-plugins/qpid-broker-plugins-jdbc-provider-bone) org.apache.qpid:qpid-broker-plugins-jdbc-provider-bone:jar
     License: Apache License, Version 2.0  (https://www.apache.org/licenses/LICENSE-2.0.txt)
   - Apache Qpid Broker-J JDBC Message Store Plug-in (http://qpid.apache.org/components/broker-plugins/qpid-broker-plugins-jdbc-store) org.apache.qpid:qpid-broker-plugins-jdbc-store:jar


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


[qpid-broker-j] 11/12: QPID-8363: [Broker-J] Fix test dependency scope

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 88a37dcb3f41ad6409865f869c41711fd5825386
Author: Alex Rudyy <or...@apache.org>
AuthorDate: Sun Sep 29 23:14:59 2019 +0100

    QPID-8363: [Broker-J] Fix test dependency scope
---
 broker-core/pom.xml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/broker-core/pom.xml b/broker-core/pom.xml
index bc926b7..c02c600 100644
--- a/broker-core/pom.xml
+++ b/broker-core/pom.xml
@@ -95,6 +95,7 @@
     <dependency>
       <groupId>org.apache.directory.server</groupId>
       <artifactId>apacheds-all</artifactId>
+      <scope>test</scope>
     </dependency>
 
     <dependency>


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


[qpid-broker-j] 01/12: QPID-8353: [Broker-J] Add TLSv1.3 into TLS protocol preferences

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 c81cea78a653020b257434a33a7b5c9946521f45
Author: Tomas Vavricka <to...@deutsche-boerse.com>
AuthorDate: Fri Sep 20 11:53:46 2019 +0200

    QPID-8353: [Broker-J] Add TLSv1.3 into TLS protocol preferences
    
    This closes #38
    
    (cherry picked from commit d9fda7d8258b63748bfd3a324411a8b1523207b5)
---
 .../qpid/server/transport/network/security/ssl/SSLUtil.java    |  6 +-----
 .../server/transport/network/security/ssl/SSLUtilTest.java     | 10 +++++-----
 2 files changed, 6 insertions(+), 10 deletions(-)

diff --git a/broker-core/src/main/java/org/apache/qpid/server/transport/network/security/ssl/SSLUtil.java b/broker-core/src/main/java/org/apache/qpid/server/transport/network/security/ssl/SSLUtil.java
index 0ffab92..01c11d3 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/transport/network/security/ssl/SSLUtil.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/transport/network/security/ssl/SSLUtil.java
@@ -43,7 +43,6 @@ import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
 import java.security.Principal;
 import java.security.PrivateKey;
-import java.security.SecureRandom;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
@@ -89,10 +88,7 @@ public class SSLUtil
     private static final Logger LOGGER = LoggerFactory.getLogger(SSLUtil.class);
 
     private static final Integer DNS_NAME_TYPE = 2;
-    private static final String[] TLS_PROTOCOL_PREFERENCES = new String[]{"TLSv1.2", "TLSv1.1", "TLS", "TLSv1"};
-
-
-    private static final SecureRandom RANDOM = new SecureRandom();
+    private static final String[] TLS_PROTOCOL_PREFERENCES = new String[]{"TLSv1.3", "TLSv1.2", "TLSv1.1", "TLS", "TLSv1"};
 
 
     private static final Constructor<?> CONSTRUCTOR;
diff --git a/broker-core/src/test/java/org/apache/qpid/server/transport/network/security/ssl/SSLUtilTest.java b/broker-core/src/test/java/org/apache/qpid/server/transport/network/security/ssl/SSLUtilTest.java
index 7498b6a..81d928a 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/transport/network/security/ssl/SSLUtilTest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/transport/network/security/ssl/SSLUtilTest.java
@@ -72,9 +72,9 @@ public class SSLUtilTest extends UnitTestBase
     {
         List<String> whiteList = Arrays.asList("TLSv1\\.[0-9]+");
         List<String> blackList = Collections.emptyList();
-        String[] enabled = {"TLS", "TLSv1.1", "TLSv1.2"};
-        String[] expected = {"TLSv1.1", "TLSv1.2"};
-        String[] supported = {"SSLv3", "TLS", "TLSv1", "TLSv1.1", "TLSv1.2"};
+        String[] enabled = {"TLS", "TLSv1.1", "TLSv1.2", "TLSv1.3"};
+        String[] expected = {"TLSv1.1", "TLSv1.2", "TLSv1.3"};
+        String[] supported = {"SSLv3", "TLS", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"};
         String[] result = SSLUtil.filterEntries(enabled, supported, whiteList, blackList);
         assertTrue("unexpected filtered list: expected " + Arrays.toString(expected) + " actual " + Arrays.toString(
                 result), Arrays.equals(expected, result));
@@ -85,9 +85,9 @@ public class SSLUtilTest extends UnitTestBase
     {
         List<String> whiteList = Arrays.asList();
         List<String> blackList = Arrays.asList("TLSv1\\.[0-9]+");
-        String[] enabled = {"TLS", "TLSv1.1", "TLSv1.2"};
+        String[] enabled = {"TLS", "TLSv1.1", "TLSv1.2", "TLSv1.3"};
         String[] expected = {"TLS"};
-        String[] supported = {"SSLv3", "TLS", "TLSv1", "TLSv1.1", "TLSv1.2"};
+        String[] supported = {"SSLv3", "TLS", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"};
         String[] result = SSLUtil.filterEntries(enabled, supported, whiteList, blackList);
         assertTrue("unexpected filtered list: expected " + Arrays.toString(expected) + " actual " + Arrays.toString(
                 result), Arrays.equals(expected, result));


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


[qpid-broker-j] 07/12: QPID-8360: [Broker-J] Clean-up code

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 cde6d07aa6cc949daabe6044fd4837503406c00f
Author: Alex Rudyy <or...@apache.org>
AuthorDate: Mon Sep 9 11:09:33 2019 +0100

    QPID-8360: [Broker-J] Clean-up code
    
    (cherry picked from commit b14b35dcf409cf252dc75cf76a28ba712649b538)
---
 .../qpid/server/logging/logback/jdbc/JDBCBrokerLogger.java     |  9 ++++-----
 .../qpid/server/logging/logback/jdbc/JDBCBrokerLoggerImpl.java |  1 -
 .../qpid/server/logging/logback/jdbc/JDBCLoggerHelper.java     |  2 +-
 .../logging/logback/jdbc/JDBCSettingsDBNameResolver.java       |  2 +-
 .../logback/jdbc/JDBCSettingsDrivenConnectionSource.java       |  5 +++--
 .../server/logging/logback/jdbc/JDBCVirtualHostLogger.java     | 10 ++++------
 .../server/logging/logback/jdbc/JDBCVirtualHostLoggerImpl.java |  1 -
 .../server/logging/logback/jdbc/InMemoryDatabaseTestBase.java  |  3 +--
 .../server/logging/logback/jdbc/JDBCBrokerLoggerImplTest.java  |  1 -
 .../qpid/server/logging/logback/jdbc/JDBCLoggerHelperTest.java |  2 +-
 .../logback/jdbc/JDBCSettingsDrivenConnectionSourceTest.java   |  2 +-
 .../logging/logback/jdbc/JDBCVirtualHostLoggerImplTest.java    |  1 -
 12 files changed, 16 insertions(+), 23 deletions(-)

diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLogger.java b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLogger.java
index 244b103..b80913b 100644
--- a/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLogger.java
+++ b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLogger.java
@@ -33,12 +33,12 @@ public interface JDBCBrokerLogger<X extends JDBCBrokerLogger<X>> extends BrokerL
     String DEFAULT_BROKER_FAIL_ON_JDBC_LOGGER_ERROR = "false";
 
     @Override
-    @ManagedAttribute(mandatory=true)
+    @ManagedAttribute(mandatory = true)
     String getConnectionUrl();
 
     @Override
-    @ManagedAttribute(defaultValue= DefaultConnectionProviderFactory.TYPE,
-            validValues = {"org.apache.qpid.server.store.jdbc.DefaultConnectionProviderFactory#getAllAvailableConnectionProviderTypes()"} )
+    @ManagedAttribute(defaultValue = DefaultConnectionProviderFactory.TYPE,
+            validValues = {"org.apache.qpid.server.store.jdbc.DefaultConnectionProviderFactory#getAllAvailableConnectionProviderTypes()"})
     String getConnectionPoolType();
 
     @Override
@@ -46,11 +46,10 @@ public interface JDBCBrokerLogger<X extends JDBCBrokerLogger<X>> extends BrokerL
     String getUsername();
 
     @Override
-    @ManagedAttribute(secure=true)
+    @ManagedAttribute(secure = true)
     String getPassword();
 
     @Override
     @ManagedAttribute
     String getTableNamePrefix();
-
 }
diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLoggerImpl.java b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLoggerImpl.java
index c371184..3bf49b6 100644
--- a/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLoggerImpl.java
+++ b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLoggerImpl.java
@@ -168,5 +168,4 @@ public class JDBCBrokerLoggerImpl extends AbstractBrokerLogger<JDBCBrokerLoggerI
     {
         _jdbcLoggerHelper.restartConnectionSourceIfExists(getAppender());
     }
-
 }
diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCLoggerHelper.java b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCLoggerHelper.java
index d6edd2b..1260210 100644
--- a/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCLoggerHelper.java
+++ b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCLoggerHelper.java
@@ -33,9 +33,9 @@ import org.apache.qpid.server.store.jdbc.JDBCSettings;
 
 class JDBCLoggerHelper
 {
-    private static final Logger LOGGER = LoggerFactory.getLogger(JDBCLoggerHelper.class);
     final static ch.qos.logback.classic.Logger ROOT_LOGGER =
             ((ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME));
+    private static final Logger LOGGER = LoggerFactory.getLogger(JDBCLoggerHelper.class);
 
     Appender<ILoggingEvent> createAppenderInstance(final Context context,
                                                    final ConfiguredObject<?> logger,
diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDBNameResolver.java b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDBNameResolver.java
index cc28635..2d071ba 100644
--- a/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDBNameResolver.java
+++ b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDBNameResolver.java
@@ -35,7 +35,7 @@ class JDBCSettingsDBNameResolver implements DBNameResolver
     @Override
     public <N extends Enum<?>> String getTableName(final N tableName)
     {
-        String settingsTableNamePrefix = _settings.getTableNamePrefix() ;
+        final String settingsTableNamePrefix = _settings.getTableNamePrefix();
         final String prefix = settingsTableNamePrefix == null ? "" : settingsTableNamePrefix;
         final String name = prefix + tableName.toString();
         return name.toLowerCase();
diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDrivenConnectionSource.java b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDrivenConnectionSource.java
index d2f76f6..5197421 100644
--- a/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDrivenConnectionSource.java
+++ b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDrivenConnectionSource.java
@@ -65,7 +65,8 @@ public class JDBCSettingsDrivenConnectionSource extends ConnectionSourceBase
     {
         _connectionProvider.getAndUpdate(provider -> provider == null ? create() : provider);
         discoverConnectionProperties();
-        if (!supportsGetGeneratedKeys() && getSQLDialectCode() == SQLDialectCode.UNKNOWN_DIALECT) {
+        if (!supportsGetGeneratedKeys() && getSQLDialectCode() == SQLDialectCode.UNKNOWN_DIALECT)
+        {
             addWarn("Connection does not support GetGeneratedKey method and could not discover the dialect.");
         }
         super.start();
@@ -76,7 +77,7 @@ public class JDBCSettingsDrivenConnectionSource extends ConnectionSourceBase
     {
         super.stop();
 
-        final ConnectionProvider connectionProvider =  _connectionProvider.getAndSet(null);
+        final ConnectionProvider connectionProvider = _connectionProvider.getAndSet(null);
         if (connectionProvider != null)
         {
             try
diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLogger.java b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLogger.java
index 76c125b..bbac661 100644
--- a/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLogger.java
+++ b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLogger.java
@@ -20,7 +20,6 @@
 package org.apache.qpid.server.logging.logback.jdbc;
 
 import org.apache.qpid.server.model.ManagedAttribute;
-import org.apache.qpid.server.model.ManagedContextDefault;
 import org.apache.qpid.server.model.VirtualHostLogger;
 import org.apache.qpid.server.store.jdbc.DefaultConnectionProviderFactory;
 import org.apache.qpid.server.store.jdbc.JDBCSettings;
@@ -28,12 +27,12 @@ import org.apache.qpid.server.store.jdbc.JDBCSettings;
 public interface JDBCVirtualHostLogger<X extends JDBCVirtualHostLogger<X>> extends VirtualHostLogger<X>, JDBCSettings
 {
     @Override
-    @ManagedAttribute(mandatory=true)
+    @ManagedAttribute(mandatory = true)
     String getConnectionUrl();
 
     @Override
-    @ManagedAttribute(defaultValue= DefaultConnectionProviderFactory.TYPE,
-            validValues = {"org.apache.qpid.server.store.jdbc.DefaultConnectionProviderFactory#getAllAvailableConnectionProviderTypes()"} )
+    @ManagedAttribute(defaultValue = DefaultConnectionProviderFactory.TYPE,
+            validValues = {"org.apache.qpid.server.store.jdbc.DefaultConnectionProviderFactory#getAllAvailableConnectionProviderTypes()"})
     String getConnectionPoolType();
 
     @Override
@@ -41,11 +40,10 @@ public interface JDBCVirtualHostLogger<X extends JDBCVirtualHostLogger<X>> exten
     String getUsername();
 
     @Override
-    @ManagedAttribute(secure=true)
+    @ManagedAttribute(secure = true)
     String getPassword();
 
     @Override
     @ManagedAttribute
     String getTableNamePrefix();
-
 }
diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLoggerImpl.java b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLoggerImpl.java
index 2a028f6..8eb0a27 100644
--- a/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLoggerImpl.java
+++ b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLoggerImpl.java
@@ -22,7 +22,6 @@ package org.apache.qpid.server.logging.logback.jdbc;
 import java.util.Map;
 import java.util.Set;
 
-import ch.qos.logback.classic.db.DBAppender;
 import ch.qos.logback.classic.spi.ILoggingEvent;
 import ch.qos.logback.core.Appender;
 import ch.qos.logback.core.Context;
diff --git a/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/InMemoryDatabaseTestBase.java b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/InMemoryDatabaseTestBase.java
index 8af8e83..6f02786 100644
--- a/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/InMemoryDatabaseTestBase.java
+++ b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/InMemoryDatabaseTestBase.java
@@ -34,7 +34,7 @@ public class InMemoryDatabaseTestBase extends UnitTestBase
     private Connection _setupConnection;
 
     @Before
-    public  void startUpDatabase() throws SQLException
+    public void startUpDatabase() throws SQLException
     {
         _setupConnection = DriverManager.getConnection(getTestDatabaseUrl());
     }
@@ -61,5 +61,4 @@ public class InMemoryDatabaseTestBase extends UnitTestBase
     {
         return _setupConnection;
     }
-
 }
diff --git a/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLoggerImplTest.java b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLoggerImplTest.java
index 48740ec..9cb8bc9 100644
--- a/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLoggerImplTest.java
+++ b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLoggerImplTest.java
@@ -146,5 +146,4 @@ public class JDBCBrokerLoggerImplTest extends InMemoryDatabaseTestBase
 
         assertEquals(TABLE_PREFIX, _logger.getTableNamePrefix());
     }
-
 }
diff --git a/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCLoggerHelperTest.java b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCLoggerHelperTest.java
index 0e03e47..bb5a335 100644
--- a/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCLoggerHelperTest.java
+++ b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCLoggerHelperTest.java
@@ -66,7 +66,7 @@ public class JDBCLoggerHelperTest extends InMemoryDatabaseTestBase
         assertTrue(appender instanceof DBAppender);
         assertTrue(appender.isStarted());
         assertEquals(context, appender.getContext());
-        assertTrue(((DBAppender)appender).getConnectionSource() instanceof JDBCSettingsDrivenConnectionSource);
+        assertTrue(((DBAppender) appender).getConnectionSource() instanceof JDBCSettingsDrivenConnectionSource);
     }
 
     @Test
diff --git a/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDrivenConnectionSourceTest.java b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDrivenConnectionSourceTest.java
index 0120452..93f212c 100644
--- a/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDrivenConnectionSourceTest.java
+++ b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDrivenConnectionSourceTest.java
@@ -43,7 +43,7 @@ public class JDBCSettingsDrivenConnectionSourceTest extends InMemoryDatabaseTest
     public void setUp()
     {
         final JDBCSettings jdbcSettings = mock(JDBCSettings.class);
-        when(jdbcSettings.getConnectionUrl()).thenReturn( getTestDatabaseUrl());
+        when(jdbcSettings.getConnectionUrl()).thenReturn(getTestDatabaseUrl());
 
         final ConfiguredObject<?> object = mock(ConfiguredObject.class);
         _connectionSource = new JDBCSettingsDrivenConnectionSource(object, jdbcSettings);
diff --git a/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLoggerImplTest.java b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLoggerImplTest.java
index ce3b00c..99a8df1 100644
--- a/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLoggerImplTest.java
+++ b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLoggerImplTest.java
@@ -134,5 +134,4 @@ public class JDBCVirtualHostLoggerImplTest extends InMemoryDatabaseTestBase
 
         assertEquals(TABLE_PREFIX, _logger.getTableNamePrefix());
     }
-
 }


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


[qpid-broker-j] 10/12: QPID-8364: [Broker-J] Add support for SPNEGO authentication

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 a9aedc74939cf781143e913398d52f2afb25eceb
Author: Alex Rudyy <or...@apache.org>
AuthorDate: Wed Sep 25 17:42:10 2019 +0100

    QPID-8364: [Broker-J] Add support for SPNEGO authentication
    
    (cherry picked from commit e4687a493b97c3bb4d1101f00139bc09c0618fda)
---
 broker-core/pom.xml                                |   6 +
 .../server/security/TokenCarryingPrincipal.java    |  27 ++
 .../manager/KerberosAuthenticationManager.java     |  82 +++++-
 .../security/auth/manager/SpnegoAuthenticator.java | 293 +++++++++++++++++++++
 .../manager/KerberosAuthenticationManagerTest.java | 262 ++++++++++++++++++
 .../auth/manager/SpnegoAuthenticatorTest.java      | 175 ++++++++++++
 .../qpid/server/test/EmbeddedKdcResource.java      | 196 ++++++++++++++
 .../apache/qpid/server/test/KerberosUtilities.java | 189 +++++++++++++
 broker-core/src/test/resources/login.config        |  25 ++
 .../server/management/plugin/HttpManagement.java   |   1 +
 .../auth/SpnegoInteractiveAuthenticator.java       | 102 +++++++
 .../plugin/auth/SpnegoPreemptiveAuthenticator.java |  63 +++++
 .../plugin/filter/AuthenticationCheckFilter.java   |   4 +
 ...-Security-Authentication-Providers-Kerberos.xml |  46 +++-
 pom.xml                                            |   8 +
 .../qpid/test/utils/SystemPropertySetter.java      |  54 ++++
 .../org/apache/qpid/test/utils/UnitTestBase.java   |  38 +--
 17 files changed, 1535 insertions(+), 36 deletions(-)

diff --git a/broker-core/pom.xml b/broker-core/pom.xml
index 7f7bd78..bc926b7 100644
--- a/broker-core/pom.xml
+++ b/broker-core/pom.xml
@@ -97,6 +97,12 @@
       <artifactId>apacheds-all</artifactId>
     </dependency>
 
+    <dependency>
+      <groupId>org.apache.kerby</groupId>
+      <artifactId>kerb-simplekdc</artifactId>
+      <scope>test</scope>
+    </dependency>
+
   </dependencies>
    
   <build>
diff --git a/broker-core/src/main/java/org/apache/qpid/server/security/TokenCarryingPrincipal.java b/broker-core/src/main/java/org/apache/qpid/server/security/TokenCarryingPrincipal.java
new file mode 100644
index 0000000..87d47a2
--- /dev/null
+++ b/broker-core/src/main/java/org/apache/qpid/server/security/TokenCarryingPrincipal.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.qpid.server.security;
+
+import java.util.Map;
+
+public interface TokenCarryingPrincipal extends QpidPrincipal
+{
+    Map<String, String> getTokens();
+}
diff --git a/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/KerberosAuthenticationManager.java b/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/KerberosAuthenticationManager.java
index 9cf4674..69a9776 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/KerberosAuthenticationManager.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/KerberosAuthenticationManager.java
@@ -18,14 +18,20 @@
  */
 package org.apache.qpid.server.security.auth.manager;
 
+import java.io.File;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
+import org.apache.qpid.server.configuration.IllegalConfigurationException;
+import org.apache.qpid.server.model.AuthenticationProvider;
+import org.apache.qpid.server.model.ConfiguredObject;
 import org.apache.qpid.server.model.Container;
 import org.apache.qpid.server.model.ManagedObject;
 import org.apache.qpid.server.model.ManagedObjectFactoryConstructor;
 import org.apache.qpid.server.model.NamedAddressSpace;
+import org.apache.qpid.server.security.auth.AuthenticationResult;
 import org.apache.qpid.server.security.auth.sasl.SaslNegotiator;
 import org.apache.qpid.server.security.auth.sasl.SaslSettings;
 import org.apache.qpid.server.security.auth.sasl.kerberos.KerberosNegotiator;
@@ -33,13 +39,38 @@ import org.apache.qpid.server.security.auth.sasl.kerberos.KerberosNegotiator;
 @ManagedObject( category = false, type = "Kerberos" )
 public class KerberosAuthenticationManager extends AbstractAuthenticationManager<KerberosAuthenticationManager>
 {
+    private static final String JAAS_CONFIG_PROPERTY = "java.security.auth.login.config";
+    private static final String GSSAPI_SERVER_NAME = "qpid.auth.gssapi.serverName";
+    private static final String GSSAPI_SPNEGO_STRIP_REALM = "qpid.auth.gssapi.spnegoStripRealmFromPrincipalName";
+    static final String GSSAPI_SPNEGO_CONFIG = "qpid.auth.gssapi.spnegoConfigScope";
     public static final String PROVIDER_TYPE = "Kerberos";
     public static final String GSSAPI_MECHANISM = "GSSAPI";
 
+    private final Container<?> _container;
+    private final SpnegoAuthenticator _authenticator;
+    private volatile String _serverName;
+    private volatile String _spnegoConfig;
+    private volatile boolean _stripRealmFromPrincipalName;
+
     @ManagedObjectFactoryConstructor
     protected KerberosAuthenticationManager(final Map<String, Object> attributes, final Container<?> container)
     {
         super(attributes, container);
+        _container = container;
+        _authenticator = new SpnegoAuthenticator(this);
+    }
+
+    @Override
+    protected void onOpen()
+    {
+        super.onOpen();
+        final Set<String> contextKeys = getContextKeys(false);
+        _serverName = contextKeys.contains(GSSAPI_SERVER_NAME) ?
+                getContextValue(String.class, GSSAPI_SERVER_NAME) : null;
+        _spnegoConfig = contextKeys.contains(GSSAPI_SPNEGO_CONFIG) ?
+                getContextValue(String.class, GSSAPI_SPNEGO_CONFIG) : null;
+        _stripRealmFromPrincipalName = contextKeys.contains(GSSAPI_SPNEGO_STRIP_REALM) ?
+                getContextValue(Boolean.class, GSSAPI_SPNEGO_STRIP_REALM) : false;
     }
 
     @Override
@@ -55,11 +86,60 @@ public class KerberosAuthenticationManager extends AbstractAuthenticationManager
     {
         if(GSSAPI_MECHANISM.equals(mechanism))
         {
-            return new KerberosNegotiator(this, saslSettings.getLocalFQDN());
+            final String serverName = _serverName == null ? saslSettings.getLocalFQDN(): _serverName;
+            return new KerberosNegotiator(this, serverName);
         }
         else
         {
             return null;
         }
     }
+
+    public AuthenticationResult authenticate(String authorizationHeader)
+    {
+        return _authenticator.authenticate(authorizationHeader);
+    }
+
+    public String getSpnegoLoginConfigScope()
+    {
+        return _spnegoConfig;
+    }
+
+    public boolean isStripRealmFromPrincipalName()
+    {
+        return _stripRealmFromPrincipalName;
+    }
+
+    @Override
+    protected void validateOnCreate()
+    {
+        super.validateOnCreate();
+        validate(this);
+    }
+
+    @Override
+    protected void validateChange(final ConfiguredObject<?> proxyForValidation, final Set<String> changedAttributes)
+    {
+        super.validateChange(proxyForValidation, changedAttributes);
+        validate(proxyForValidation);
+    }
+
+    private void validate(final ConfiguredObject<?> authenticationProvider)
+    {
+        final String config = System.getProperty(JAAS_CONFIG_PROPERTY);
+        if (config != null && !new File(config).exists())
+        {
+            throw new IllegalConfigurationException(String.format(
+                    "A path to non-existing file is specified in JVM system property '%s'", JAAS_CONFIG_PROPERTY));
+        }
+
+        if (_container.getChildren(AuthenticationProvider.class)
+                      .stream()
+                      .anyMatch(p -> p instanceof KerberosAuthenticationManager
+                                     && p != authenticationProvider))
+        {
+            throw new IllegalConfigurationException("Another Kerberos authentication provider already exists."
+                                                    + " Only one Kerberos authentication provider can be created.");
+        }
+    }
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SpnegoAuthenticator.java b/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SpnegoAuthenticator.java
new file mode 100644
index 0000000..48cf4f9
--- /dev/null
+++ b/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SpnegoAuthenticator.java
@@ -0,0 +1,293 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.qpid.server.security.auth.manager;
+
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.Map;
+
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
+import com.google.common.base.StandardSystemProperty;
+import org.ietf.jgss.GSSContext;
+import org.ietf.jgss.GSSCredential;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.GSSManager;
+import org.ietf.jgss.GSSName;
+import org.ietf.jgss.Oid;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.security.TokenCarryingPrincipal;
+import org.apache.qpid.server.security.auth.AuthenticationResult;
+
+public class SpnegoAuthenticator
+{
+    private static final Logger LOGGER = LoggerFactory.getLogger(SpnegoAuthenticator.class);
+    public static final String REQUEST_AUTH_HEADER_NAME = "Authorization";
+    public static final String RESPONSE_AUTH_HEADER_NAME = "WWW-Authenticate";
+    public static final String RESPONSE_AUTH_HEADER_VALUE_NEGOTIATE = "Negotiate";
+    public static final String AUTH_TYPE = "SPNEGO";
+    static final String NEGOTIATE_PREFIX = "Negotiate ";
+    private final KerberosAuthenticationManager _kerberosProvider;
+
+    SpnegoAuthenticator(final KerberosAuthenticationManager kerberosProvider)
+    {
+        _kerberosProvider = kerberosProvider;
+    }
+
+    public AuthenticationResult authenticate(String authorizationHeader)
+    {
+        if (authorizationHeader == null)
+        {
+            if (LOGGER.isDebugEnabled())
+            {
+                LOGGER.debug("'Authorization' header is not set");
+            }
+            return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR);
+        }
+        else
+        {
+            if (!hasNegotiatePrefix(authorizationHeader))
+            {
+                if (LOGGER.isDebugEnabled())
+                {
+                    LOGGER.debug("'Authorization' header value does not start with '{}'", NEGOTIATE_PREFIX);
+                }
+                return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR);
+            }
+            else
+            {
+                final String negotiateToken = authorizationHeader.substring(NEGOTIATE_PREFIX.length());
+                final byte[] decodedNegotiateHeader;
+                try
+                {
+                    decodedNegotiateHeader = Base64.getDecoder().decode(negotiateToken);
+                }
+                catch (RuntimeException e)
+                {
+                    if (LOGGER.isDebugEnabled())
+                    {
+                        LOGGER.debug("Ticket decoding failed", e);
+                    }
+                    return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR);
+                }
+
+                if (decodedNegotiateHeader.length == 0)
+                {
+                    if (LOGGER.isDebugEnabled())
+                    {
+                        LOGGER.debug("Empty ticket");
+                    }
+                    return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR);
+                }
+                else
+                {
+                    return authenticate(decodedNegotiateHeader);
+                }
+            }
+        }
+    }
+
+    private boolean hasNegotiatePrefix(final String authorizationHeader)
+    {
+        if (authorizationHeader.length() > NEGOTIATE_PREFIX.length() )
+        {
+            return NEGOTIATE_PREFIX.equalsIgnoreCase(authorizationHeader.substring(0, NEGOTIATE_PREFIX.length()));
+        }
+        return false;
+    }
+
+    public AuthenticationResult authenticate(byte[] negotiateToken)
+    {
+        LoginContext loginContext = null;
+        try
+        {
+            loginContext = new LoginContext(_kerberosProvider.getSpnegoLoginConfigScope());
+            loginContext.login();
+            Subject subject = loginContext.getSubject();
+
+            return doAuthenticate(subject, negotiateToken);
+        }
+        catch (LoginException e)
+        {
+            LOGGER.error("JASS login failed", e);
+            return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR, e);
+        }
+        finally
+        {
+            if (loginContext != null)
+            {
+                try
+                {
+                    loginContext.logout();
+                }
+                catch (LoginException e)
+                {
+                    // Ignore
+                }
+            }
+        }
+    }
+
+    private AuthenticationResult doAuthenticate(final Subject subject, final byte[] negotiateToken)
+    {
+        GSSContext context = null;
+        try
+        {
+
+            final int credentialLifetime;
+            if (String.valueOf(System.getProperty(StandardSystemProperty.JAVA_VENDOR.key()))
+                      .toUpperCase()
+                      .contains("IBM"))
+            {
+                credentialLifetime = GSSCredential.INDEFINITE_LIFETIME;
+            }
+            else
+            {
+                credentialLifetime = GSSCredential.DEFAULT_LIFETIME;
+            }
+
+            final GSSManager manager = GSSManager.getInstance();
+            final PrivilegedExceptionAction<GSSCredential> credentialsAction =
+                    () -> manager.createCredential(null,
+                                                   credentialLifetime,
+                                                   new Oid("1.3.6.1.5.5.2"),
+                                                   GSSCredential.ACCEPT_ONLY);
+            final GSSContext gssContext = manager.createContext(Subject.doAs(subject, credentialsAction));
+            context = gssContext;
+
+            final PrivilegedExceptionAction<byte[]> acceptAction =
+                    () -> gssContext.acceptSecContext(negotiateToken, 0, negotiateToken.length);
+            final byte[] outToken = Subject.doAs(subject, acceptAction);
+
+            if (outToken == null)
+            {
+                LOGGER.debug("Ticket validation failed");
+                return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR);
+            }
+
+            final PrivilegedAction<String> authenticationAction = () -> {
+                if (gssContext.isEstablished())
+                {
+                    GSSName gssName = null;
+                    try
+                    {
+                        gssName = gssContext.getSrcName();
+                    }
+                    catch (final GSSException e)
+                    {
+                        LOGGER.error("Unable to get src name from gss context", e);
+                    }
+
+                    if (gssName != null)
+                    {
+                        return stripRealmNameIfRequired(gssName.toString());
+                    }
+                }
+                return null;
+            };
+            final String principalName = Subject.doAs(subject, authenticationAction);
+            if (principalName != null)
+            {
+                TokenCarryingPrincipal principal = new TokenCarryingPrincipal()
+                {
+                    @Override
+                    public Map<String, String> getTokens()
+                    {
+                        return Collections.singletonMap(RESPONSE_AUTH_HEADER_NAME,
+                                                        NEGOTIATE_PREFIX + Base64.getEncoder().encodeToString(outToken));
+                    }
+
+                    @Override
+                    public ConfiguredObject<?> getOrigin()
+                    {
+                        return _kerberosProvider;
+                    }
+
+                    @Override
+                    public String getName()
+                    {
+                        return principalName;
+                    }
+                };
+                return new AuthenticationResult(principal);
+            }
+            return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR);
+        }
+        catch (GSSException e)
+        {
+            if (LOGGER.isDebugEnabled())
+            {
+                LOGGER.debug("Ticket validation failed", e);
+            }
+            return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR, e);
+        }
+        catch (PrivilegedActionException e)
+        {
+            final Exception cause = e.getException();
+            if (cause instanceof GSSException)
+            {
+                if (LOGGER.isDebugEnabled())
+                {
+                    LOGGER.debug("Service login failed", e);
+                }
+            }
+            else
+            {
+                LOGGER.error("Service login failed", e);
+            }
+            return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR, e);
+        }
+        finally
+        {
+            if (context != null)
+            {
+                try
+                {
+                    context.dispose();
+                }
+                catch (GSSException e)
+                {
+                    // Ignore
+                }
+            }
+        }
+    }
+
+    private String stripRealmNameIfRequired(String name)
+    {
+        if (_kerberosProvider.isStripRealmFromPrincipalName() && name != null)
+        {
+            final int i = name.indexOf('@');
+            if (i > 0)
+            {
+                name = name.substring(0, i);
+            }
+        }
+        return name;
+    }
+}
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
new file mode 100644
index 0000000..4fb6293
--- /dev/null
+++ b/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/KerberosAuthenticationManagerTest.java
@@ -0,0 +1,262 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.qpid.server.security.auth.manager;
+
+import static org.apache.qpid.server.security.auth.manager.KerberosAuthenticationManager.GSSAPI_MECHANISM;
+import static org.hamcrest.Matchers.not;
+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.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.security.auth.Subject;
+import javax.security.auth.kerberos.KerberosPrincipal;
+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;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.BrokerTestHelper;
+import org.apache.qpid.server.security.auth.AuthenticationResult;
+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.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);
+
+    @ClassRule
+    public static final SystemPropertySetter SYSTEM_PROPERTY_SETTER = new SystemPropertySetter();
+
+    private static File _clientKeyTabFile;
+
+    private KerberosAuthenticationManager _kerberosAuthenticationProvider;
+    private Broker<?> _broker;
+
+    @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", resource.getPath());
+        SYSTEM_PROPERTY_SETTER.setSystemProperty("javax.security.auth.useSubjectCredsOnly", "false");
+    }
+
+    @Before
+    public void setUp() throws Exception
+    {
+        Map<String, String> context = Collections.singletonMap(KerberosAuthenticationManager.GSSAPI_SPNEGO_CONFIG,
+                                                               "com.sun.security.jgss.accept");
+        final Map<String, Object> attributes = new HashMap<>();
+        attributes.put(AuthenticationProvider.NAME, getTestName());
+        attributes.put(AuthenticationProvider.CONTEXT, context);
+        _broker = BrokerTestHelper.createBrokerMock();
+        _kerberosAuthenticationProvider = new KerberosAuthenticationManager(attributes, _broker);
+        _kerberosAuthenticationProvider.create();
+        when(_broker.getChildren(AuthenticationProvider.class))
+                .thenReturn(Collections.singleton(_kerberosAuthenticationProvider));
+    }
+
+    @Test
+    public void testCreateSaslNegotiator() throws Exception
+    {
+        final SaslSettings saslSettings = mock(SaslSettings.class);
+        when(saslSettings.getLocalFQDN()).thenReturn(SERVER_NAME);
+        final SaslNegotiator negotiator = _kerberosAuthenticationProvider.createSaslNegotiator(GSSAPI_MECHANISM,
+                                                                                               saslSettings,
+                                                                                               null);
+        assertNotNull("Could not create SASL negotiator", negotiator);
+        try
+        {
+            final AuthenticationResult result = authenticate(negotiator);
+            assertEquals(AuthenticationResult.AuthenticationStatus.SUCCESS, result.getStatus());
+            assertEquals(new KerberosPrincipal(CLIENT_PRINCIPAL_FULL_NAME).getName(),
+                         result.getMainPrincipal().getName());
+        }
+        finally
+        {
+            negotiator.dispose();
+        }
+    }
+
+    @Test
+    public void testSeveralKerberosAuthenticationProviders()
+    {
+        final Map<String, Object> attributes =
+                Collections.singletonMap(AuthenticationProvider.NAME, getTestName() + "2");
+        final KerberosAuthenticationManager kerberosAuthenticationProvider =
+                new KerberosAuthenticationManager(attributes, _broker);
+        try
+        {
+            kerberosAuthenticationProvider.create();
+            fail("Exception expected");
+        }
+        catch (IllegalConfigurationException e)
+        {
+            // pass
+        }
+    }
+
+    @Test
+    public void testCreateKerberosAuthenticationProvidersWithNonExistingJaasLoginModule()
+    {
+        when(_broker.getChildren(AuthenticationProvider.class)).thenReturn(Collections.emptySet());
+        SYSTEM_PROPERTY_SETTER.setSystemProperty("java.security.auth.login.config",
+                                                 "config.module." + System.nanoTime());
+        final Map<String, Object> attributes = Collections.singletonMap(AuthenticationProvider.NAME, getTestName());
+        final KerberosAuthenticationManager kerberosAuthenticationProvider =
+                new KerberosAuthenticationManager(attributes, _broker);
+        try
+        {
+            kerberosAuthenticationProvider.create();
+            fail("Exception expected");
+        }
+        catch (IllegalConfigurationException e)
+        {
+            // pass
+        }
+    }
+
+    @Test
+    public void testAuthenticateUsingNegotiationToken() throws GSSException
+    {
+        final String token =
+                Base64.getEncoder().encodeToString(UTILS.buildToken(CLIENT_PRINCIPAL_NAME, SERVICE_PRINCIPAL_NAME));
+        final String authenticationHeader = SpnegoAuthenticator.NEGOTIATE_PREFIX + token;
+
+        final AuthenticationResult result = _kerberosAuthenticationProvider.authenticate(authenticationHeader);
+
+        assertNotNull(result);
+        assertEquals(AuthenticationResult.AuthenticationStatus.SUCCESS, result.getStatus());
+    }
+
+    private AuthenticationResult authenticate(final SaslNegotiator negotiator) throws Exception
+    {
+        final LoginContext lc = UTILS.createKerberosKeyTabLoginContext(getTestName(),
+                                                                       CLIENT_PRINCIPAL_FULL_NAME,
+                                                                       _clientKeyTabFile);
+        try
+        {
+            lc.login();
+            final Subject clientSubject = lc.getSubject();
+            final SaslClient saslClient = createSaslClient(clientSubject);
+            return performNegotiation(clientSubject, saslClient, negotiator);
+        }
+        finally
+        {
+            lc.logout();
+        }
+    }
+
+    private AuthenticationResult performNegotiation(final Subject clientSubject,
+                                                    final SaslClient saslClient,
+                                                    final SaslNegotiator negotiator)
+            throws PrivilegedActionException
+    {
+        AuthenticationResult result;
+        byte[] response = null;
+        boolean initiated = false;
+        do
+        {
+            if (!initiated)
+            {
+                initiated = true;
+                response = Subject.doAs(clientSubject, (PrivilegedExceptionAction<byte[]>) () -> {
+                    if (saslClient.hasInitialResponse())
+                    {
+                        return saslClient.evaluateChallenge(new byte[0]);
+                    }
+                    return null;
+                });
+            }
+
+            result = negotiator.handleResponse(response);
+
+            byte[] challenge = result.getChallenge();
+            if (challenge != null)
+            {
+                response = Subject.doAs(clientSubject,
+                                        (PrivilegedExceptionAction<byte[]>) () -> saslClient.evaluateChallenge(
+                                                challenge));
+            }
+        }
+        while (result.getStatus() == AuthenticationResult.AuthenticationStatus.CONTINUE);
+        return result;
+    }
+
+    private SaslClient createSaslClient(final Subject clientSubject) throws PrivilegedActionException
+    {
+        return Subject.doAs(clientSubject, (PrivilegedExceptionAction<SaslClient>) () -> {
+
+            final Map<String, String> props =
+                    Collections.singletonMap("javax.security.sasl.server.authentication", "true");
+
+            return Sasl.createSaslClient(new String[]{GSSAPI_MECHANISM},
+                                         null,
+                                         SERVER_PROTOCOL,
+                                         SERVER_NAME,
+                                         props,
+                                         null);
+        });
+    }
+}
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
new file mode 100644
index 0000000..5b34736
--- /dev/null
+++ b/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SpnegoAuthenticatorTest.java
@@ -0,0 +1,175 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.qpid.server.security.auth.manager;
+
+import static org.hamcrest.Matchers.not;
+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.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();;
+
+    @ClassRule
+    public static final EmbeddedKdcResource KDC = new EmbeddedKdcResource(REALM);
+
+    @ClassRule
+    public static final SystemPropertySetter SYSTEM_PROPERTY_SETTER = new SystemPropertySetter();
+
+    private SpnegoAuthenticator _spnegoAuthenticator;
+    private KerberosAuthenticationManager _kerberosAuthenticationManager;
+
+    @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", resource.getPath());
+        SYSTEM_PROPERTY_SETTER.setSystemProperty("javax.security.auth.useSubjectCredsOnly", "false");
+    }
+
+    @Before
+    public void setUp()
+    {
+        _kerberosAuthenticationManager = mock(KerberosAuthenticationManager.class);
+        when(_kerberosAuthenticationManager.getSpnegoLoginConfigScope()).thenReturn("com.sun.security.jgss.accept");
+        when(_kerberosAuthenticationManager.isStripRealmFromPrincipalName()).thenReturn(true);
+
+        _spnegoAuthenticator = new SpnegoAuthenticator(_kerberosAuthenticationManager);
+    }
+
+    @Test
+    public void testAuthenticate() throws GSSException
+    {
+        final String token = Base64.getEncoder().encodeToString(buildToken(SERVER_NAME));
+        final String authenticationHeader = SpnegoAuthenticator.NEGOTIATE_PREFIX + token;
+
+        final AuthenticationResult result = _spnegoAuthenticator.authenticate(authenticationHeader);
+
+        assertNotNull(result);
+        assertEquals(AuthenticationResult.AuthenticationStatus.SUCCESS, result.getStatus());
+        final Principal principal = result.getMainPrincipal();
+        assertTrue(principal instanceof TokenCarryingPrincipal);
+        assertEquals(CLIENT_NAME, principal.getName());
+
+        final Map<String, String> tokens = ((TokenCarryingPrincipal)principal).getTokens();
+        assertNotNull(tokens);
+        assertTrue(tokens.containsKey(SpnegoAuthenticator.RESPONSE_AUTH_HEADER_NAME));
+    }
+
+    @Test
+    public void testAuthenticateNoAuthenticationHeader()
+    {
+        final AuthenticationResult result = _spnegoAuthenticator.authenticate((String) null);
+        assertNotNull(result);
+        assertEquals(AuthenticationResult.AuthenticationStatus.ERROR, result.getStatus());
+    }
+
+    @Test
+    public void testAuthenticateNoNegotiatePrefix() throws GSSException
+    {
+        final String token = Base64.getEncoder().encodeToString(buildToken(SERVER_NAME));
+        final AuthenticationResult result = _spnegoAuthenticator.authenticate(token);
+        assertNotNull(result);
+        assertEquals(AuthenticationResult.AuthenticationStatus.ERROR, result.getStatus());
+    }
+
+    @Test
+    public void testAuthenticateEmptyToken()
+    {
+        final AuthenticationResult result =
+                _spnegoAuthenticator.authenticate(SpnegoAuthenticator.NEGOTIATE_PREFIX + "");
+        assertNotNull(result);
+        assertEquals(AuthenticationResult.AuthenticationStatus.ERROR, result.getStatus());
+    }
+
+    @Test
+    public void testAuthenticateInvalidToken()
+    {
+        final AuthenticationResult result =
+                _spnegoAuthenticator.authenticate(SpnegoAuthenticator.NEGOTIATE_PREFIX + "Zm9v");
+        assertNotNull(result);
+        assertEquals(AuthenticationResult.AuthenticationStatus.ERROR, result.getStatus());
+    }
+
+    @Test
+    public void testAuthenticateWrongConfigName() throws GSSException
+    {
+        when(_kerberosAuthenticationManager.getSpnegoLoginConfigScope()).thenReturn("foo");
+        final String token = Base64.getEncoder().encodeToString(buildToken(SERVER_NAME));
+        final String authenticationHeader = SpnegoAuthenticator.NEGOTIATE_PREFIX + token;
+
+        final AuthenticationResult result = _spnegoAuthenticator.authenticate(authenticationHeader);
+        assertNotNull(result);
+        assertEquals(AuthenticationResult.AuthenticationStatus.ERROR, result.getStatus());
+    }
+
+    @Test
+    public void testAuthenticateWrongServer() throws GSSException
+    {
+        final String token = Base64.getEncoder().encodeToString(buildToken(ANOTHER_SERVICE));
+        final String authenticationHeader = SpnegoAuthenticator.NEGOTIATE_PREFIX + token;
+
+        final AuthenticationResult result = _spnegoAuthenticator.authenticate(authenticationHeader);
+        assertNotNull(result);
+        assertEquals(AuthenticationResult.AuthenticationStatus.ERROR, result.getStatus());
+    }
+
+    private byte[] buildToken(final String anotherService) throws GSSException
+    {
+        return UTILS.buildToken(CLIENT_NAME, 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
new file mode 100644
index 0000000..cda31a8
--- /dev/null
+++ b/broker-core/src/test/java/org/apache/qpid/server/test/EmbeddedKdcResource.java
@@ -0,0 +1,196 @@
+/*
+ * 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.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.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.server.KdcConfigKey;
+import org.apache.kerby.kerberos.kerb.server.SimpleKdcServer;
+import org.junit.rules.ExternalResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class EmbeddedKdcResource extends ExternalResource
+{
+    private static final Logger LOGGER = LoggerFactory.getLogger(EmbeddedKdcResource.class);
+    private final SimpleKdcServer _simpleKdcServer;
+    private final String _realm;
+    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;
+        try
+        {
+            _simpleKdcServer = new SimpleKdcServer();
+            _simpleKdcServer.setKdcHost(host);
+            if (port > 0)
+            {
+                _simpleKdcServer.setKdcTcpPort(port);
+            }
+            _simpleKdcServer.setAllowUdp(false);
+            _simpleKdcServer.setKdcRealm(realm);
+            _simpleKdcServer.getKdcConfig().setString(KdcConfigKey.KDC_SERVICE_NAME, serviceName);
+        }
+        catch (KrbException e)
+        {
+            throw new AssertionError(String.format("Unable to create SimpleKdcServer': %s", e.getMessage()), e);
+        }
+    }
+
+    @Override
+    public void before() throws Exception
+    {
+        final Path targetDir = FileSystems.getDefault().getPath("target");
+        _kdcDirectory = Files.createTempDirectory(targetDir, "simple-kdc-").toFile();
+        _simpleKdcServer.setWorkDir(_kdcDirectory);
+        _simpleKdcServer.init();
+        _simpleKdcServer.start();
+    }
+
+    @Override
+    public void after()
+    {
+        try
+        {
+            _simpleKdcServer.stop();
+        }
+        catch (KrbException e)
+        {
+            LOGGER.warn("Failure to stop KDC server", e);
+        }
+        finally
+        {
+            try
+            {
+                delete(_kdcDirectory);
+            }
+            catch (IOException e)
+            {
+                LOGGER.warn("Failure to delete KDC directory", e);
+            }
+            for (File f: _createdFiles)
+            {
+                if (!f.delete())
+                {
+                    LOGGER.warn("Failure to delete file {}", f.getAbsolutePath());
+                }
+            }
+        }
+    }
+
+    public String getRealm()
+    {
+        return _realm;
+    }
+
+    private void delete(File f) throws IOException
+    {
+        Files.walkFileTree(f.toPath(),
+                           new SimpleFileVisitor<Path>()
+                           {
+                               @Override
+                               public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs)
+                                       throws IOException
+                               {
+                                   Files.delete(file);
+                                   return FileVisitResult.CONTINUE;
+                               }
+
+                               @Override
+                               public FileVisitResult postVisitDirectory(final Path dir, final IOException exc)
+                                       throws IOException
+                               {
+                                   Files.delete(dir);
+                                   return FileVisitResult.CONTINUE;
+                               }
+                           });
+    }
+
+    public int getPort()
+    {
+        return _simpleKdcServer.getKdcTcpPort();
+    }
+
+    public File createPrincipal(String keyTabFileName, String... principals)
+            throws Exception
+    {
+        final File ketTabFile = createFile(keyTabFileName);
+        _createdFiles.add(ketTabFile);
+        createPrincipal(ketTabFile, principals);
+        return ketTabFile;
+    }
+
+    public void createPasswordPrincipal(String name, String password)
+            throws Exception
+    {
+        _simpleKdcServer.createPrincipal(name, password);
+    }
+
+    private void createPrincipal(File keyTabFile, String... principals)
+            throws Exception
+    {
+        _simpleKdcServer.createPrincipals(principals);
+        if (keyTabFile.exists() && !keyTabFile.delete())
+        {
+            LOGGER.error("Failed to delete keytab file: " + keyTabFile);
+        }
+        for (String principal : principals)
+        {
+            _simpleKdcServer.getKadmin().exportKeytab(keyTabFile, principal);
+        }
+    }
+
+    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
new file mode 100644
index 0000000..182df06
--- /dev/null
+++ b/broker-core/src/test/java/org/apache/qpid/server/test/KerberosUtilities.java
@@ -0,0 +1,189 @@
+/*
+ * 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.test;
+
+import static java.lang.Boolean.TRUE;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.security.auth.DestroyFailedException;
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.TextOutputCallback;
+import javax.security.auth.kerberos.KerberosKey;
+import javax.security.auth.kerberos.KerberosPrincipal;
+import javax.security.auth.kerberos.KeyTab;
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
+import org.ietf.jgss.GSSContext;
+import org.ietf.jgss.GSSCredential;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.GSSManager;
+import org.ietf.jgss.GSSName;
+import org.ietf.jgss.Oid;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class KerberosUtilities
+{
+    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;
+
+    public byte[] buildToken(String clientPrincipalName, String targetServerPrincipalName) throws GSSException
+    {
+        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 GSSName serverName = manager.createName(targetServerPrincipalName, GSSName.NT_USER_NAME);
+        final Oid spnegoMechOid = new Oid("1.3.6.1.5.5.2");
+        final GSSContext clientContext = manager.createContext(serverName.canonicalize(spnegoMechOid),
+                                                               spnegoMechOid,
+                                                               credential,
+                                                               GSSContext.DEFAULT_LIFETIME);
+        try
+        {
+            clientContext.requestCredDeleg(true);
+            return clientContext.initSecContext(new byte[]{}, 0, 0);
+        }
+        finally
+        {
+            clientContext.dispose();
+        }
+    }
+
+    public LoginContext createKerberosKeyTabLoginContext(final String scopeName,
+                                                         final String principalName,
+                                                         final File keyTabFile)
+            throws LoginException
+    {
+        final KerberosPrincipal principal = new KerberosPrincipal(principalName);
+        final KeyTab keyTab = getKeyTab(principal, keyTabFile);
+        final Subject subject = new Subject(false,
+                                            Collections.singleton(principal),
+                                            Collections.emptySet(),
+                                            Collections.singleton(keyTab));
+
+        return createLoginContext(scopeName,
+                                  subject,
+                                  createKeyTabConfiguration(scopeName, keyTabFile, principal.getName()));
+    }
+
+    public KerberosKeyTabLoginConfiguration createKeyTabConfiguration(final String scopeName,
+                                                                      final File keyTabFile,
+                                                                      final String name)
+    {
+        return new KerberosKeyTabLoginConfiguration(scopeName, name, keyTabFile);
+    }
+
+
+    private LoginContext createLoginContext(final String serviceName, final Subject subject, final Configuration config)
+            throws LoginException
+    {
+        return new LoginContext(serviceName, subject, callbacks -> {
+            for (Callback callback : callbacks)
+            {
+                if (callback instanceof TextOutputCallback)
+                {
+                    LOGGER.error(((TextOutputCallback) callback).getMessage());
+                }
+            }
+        }, config);
+    }
+
+
+    private KeyTab getKeyTab(final KerberosPrincipal principal, final File keyTabFile)
+    {
+        if (!keyTabFile.exists() || !keyTabFile.canRead())
+        {
+            throw new IllegalArgumentException("Specified file does not exist or is not readable.");
+        }
+
+        final KeyTab keytab = KeyTab.getInstance(principal, keyTabFile);
+        if (!keytab.exists())
+        {
+            throw new IllegalArgumentException("Specified file is not a keyTab file.");
+        }
+
+        final KerberosKey[] keys = keytab.getKeys(principal);
+        if (keys.length == 0)
+        {
+            throw new IllegalArgumentException("Specified file does not contain at least one key for this principal.");
+        }
+
+        for (final KerberosKey key : keys)
+        {
+            try
+            {
+                key.destroy();
+            }
+            catch (DestroyFailedException e)
+            {
+                LOGGER.debug("Unable to destroy key", e);
+            }
+        }
+
+        return keytab;
+    }
+
+    public static class KerberosKeyTabLoginConfiguration extends Configuration
+    {
+        private final String _scopeName;
+        private final AppConfigurationEntry _entry;
+
+        KerberosKeyTabLoginConfiguration(final String scopeName,
+                                         final String principalName,
+                                         final File keyTabFile)
+        {
+            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());
+            _entry = new AppConfigurationEntry(KERBEROS_LOGIN_MODULE_CLASS,
+                                               AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
+                                               options);
+            _scopeName = scopeName;
+        }
+
+        @Override
+        public AppConfigurationEntry[] getAppConfigurationEntry(String name)
+        {
+            if (_scopeName.equals(name))
+            {
+                return new AppConfigurationEntry[]{_entry};
+            }
+            return new AppConfigurationEntry[0];
+        }
+    }
+}
diff --git a/broker-core/src/test/resources/login.config b/broker-core/src/test/resources/login.config
index d458516..4103d07 100644
--- a/broker-core/src/test/resources/login.config
+++ b/broker-core/src/test/resources/login.config
@@ -53,3 +53,28 @@ qpid-broker-j {
     principal="service/localhost"
     keyTab="target/kerberos.keytab";
 };
+
+com.sun.security.jgss.accept {
+    com.sun.security.auth.module.Krb5LoginModule required
+    useKeyTab=true
+    storeKey=true
+    doNotPrompt=true
+    isInitiator=false
+    debug=true
+    refreshKrb5Config=true
+    realm="QPID.ORG"
+    principal="AMQP/localhost"
+    keyTab="target/broker.keytab";
+};
+
+com.sun.security.jgss.initiate {
+    com.sun.security.auth.module.Krb5LoginModule required
+    useKeyTab=true
+    storeKey=true
+    doNotPrompt=true
+    debug=true
+    refreshKrb5Config=true
+    realm="QPID.ORG"
+    principal="client"
+    keyTab="target/client.keytab";
+};
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 b76ab9d..f9d7517 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
@@ -140,6 +140,7 @@ public class HttpManagement extends AbstractPluginAdapter<HttpManagement> implem
     public static final String PLUGIN_TYPE = "MANAGEMENT-HTTP";
 
     public static final String DEFAULT_LOGOUT_URL = "/logout.html";
+    public static final String DEFAULT_LOGIN_URL = "/index.html";
 
     private static final String OPERATIONAL_LOGGING_NAME = "Web";
 
diff --git a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/auth/SpnegoInteractiveAuthenticator.java b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/auth/SpnegoInteractiveAuthenticator.java
new file mode 100644
index 0000000..004a8f4
--- /dev/null
+++ b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/auth/SpnegoInteractiveAuthenticator.java
@@ -0,0 +1,102 @@
+/*
+ * 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.auth;
+
+import java.security.Principal;
+
+import javax.security.auth.Subject;
+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;
+import org.apache.qpid.server.management.plugin.HttpManagementUtil;
+import org.apache.qpid.server.management.plugin.HttpRequestInteractiveAuthenticator;
+import org.apache.qpid.server.model.AuthenticationProvider;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.plugin.PluggableService;
+import org.apache.qpid.server.security.SubjectCreator;
+import org.apache.qpid.server.security.TokenCarryingPrincipal;
+import org.apache.qpid.server.security.auth.AuthenticationResult;
+import org.apache.qpid.server.security.auth.SubjectAuthenticationResult;
+import org.apache.qpid.server.security.auth.manager.KerberosAuthenticationManager;
+import org.apache.qpid.server.security.auth.manager.SpnegoAuthenticator;
+
+@PluggableService
+public class SpnegoInteractiveAuthenticator implements HttpRequestInteractiveAuthenticator
+{
+
+    @Override
+    public AuthenticationHandler getAuthenticationHandler(final HttpServletRequest request,
+                                                          final HttpManagementConfiguration configuration)
+    {
+        final AuthenticationProvider authenticationProvider = configuration.getAuthenticationProvider(request);
+        if (authenticationProvider instanceof KerberosAuthenticationManager)
+        {
+            final KerberosAuthenticationManager kerberosProvider =
+                    (KerberosAuthenticationManager) authenticationProvider;
+            return response -> {
+                final String authorizationHeader = request.getHeader(SpnegoAuthenticator.REQUEST_AUTH_HEADER_NAME);
+                final AuthenticationResult authenticationResult = kerberosProvider.authenticate(authorizationHeader);
+                if (authenticationResult == null
+                    || authenticationResult.getStatus() == AuthenticationResult.AuthenticationStatus.ERROR)
+                {
+                    response.setHeader(SpnegoAuthenticator.RESPONSE_AUTH_HEADER_NAME,
+                                       SpnegoAuthenticator.RESPONSE_AUTH_HEADER_VALUE_NEGOTIATE);
+                    response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
+                }
+                else
+                {
+                    final Principal principal = authenticationResult.getMainPrincipal();
+                    if (principal instanceof TokenCarryingPrincipal)
+                    {
+                        ((TokenCarryingPrincipal) principal).getTokens().forEach(response::setHeader);
+                    }
+
+                    final Port<?> port = configuration.getPort(request);
+                    final SubjectCreator subjectCreator = port.getSubjectCreator(request.isSecure(), request.getServerName());
+                    final SubjectAuthenticationResult result = subjectCreator.createResultWithGroups(authenticationResult);
+                    final Subject subject = HttpManagementUtil.createServletConnectionSubject(request, result.getSubject());
+
+                    final Broker broker = (Broker) kerberosProvider.getParent();
+                    HttpManagementUtil.assertManagementAccess(broker, subject);
+                    HttpManagementUtil.saveAuthorisedSubject(request, subject);
+                    request.getRequestDispatcher(HttpManagement.DEFAULT_LOGIN_URL).forward(request, response);
+                }
+            };
+        }
+        return null;
+    }
+
+
+    @Override
+    public LogoutHandler getLogoutHandler(final HttpServletRequest request,
+                                          final HttpManagementConfiguration configuration)
+    {
+        return response -> response.sendRedirect(HttpManagement.DEFAULT_LOGOUT_URL);
+    }
+
+    @Override
+    public String getType()
+    {
+        return SpnegoAuthenticator.AUTH_TYPE;
+    }
+}
diff --git a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/auth/SpnegoPreemptiveAuthenticator.java b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/auth/SpnegoPreemptiveAuthenticator.java
new file mode 100644
index 0000000..35c070e
--- /dev/null
+++ b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/auth/SpnegoPreemptiveAuthenticator.java
@@ -0,0 +1,63 @@
+/*
+ * 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.auth;
+
+import javax.security.auth.Subject;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.qpid.server.management.plugin.HttpManagementConfiguration;
+import org.apache.qpid.server.management.plugin.HttpRequestPreemptiveAuthenticator;
+import org.apache.qpid.server.model.AuthenticationProvider;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.plugin.PluggableService;
+import org.apache.qpid.server.security.SubjectCreator;
+import org.apache.qpid.server.security.auth.AuthenticationResult;
+import org.apache.qpid.server.security.auth.manager.SpnegoAuthenticator;
+import org.apache.qpid.server.security.auth.SubjectAuthenticationResult;
+import org.apache.qpid.server.security.auth.manager.KerberosAuthenticationManager;
+
+@PluggableService
+public class SpnegoPreemptiveAuthenticator implements HttpRequestPreemptiveAuthenticator
+{
+
+    @Override
+    public Subject attemptAuthentication(final HttpServletRequest request,
+                                         final HttpManagementConfiguration configuration)
+    {
+        final AuthenticationProvider<?> authenticationProvider = configuration.getAuthenticationProvider(request);
+        if (authenticationProvider instanceof KerberosAuthenticationManager)
+        {
+            final KerberosAuthenticationManager kerberosProvider = (KerberosAuthenticationManager) authenticationProvider;
+            final String authorizationHeader = request.getHeader(SpnegoAuthenticator.REQUEST_AUTH_HEADER_NAME);
+            final AuthenticationResult authenticationResult = kerberosProvider.authenticate(authorizationHeader);
+            final Port<?> port = configuration.getPort(request);
+            final SubjectCreator subjectCreator = port.getSubjectCreator(request.isSecure(), request.getServerName());
+            final SubjectAuthenticationResult result = subjectCreator.createResultWithGroups(authenticationResult);
+            return result.getSubject();
+        }
+        return null;
+    }
+
+    @Override
+    public String getType()
+    {
+        return SpnegoAuthenticator.AUTH_TYPE;
+    }
+}
diff --git a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/filter/AuthenticationCheckFilter.java b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/filter/AuthenticationCheckFilter.java
index b8f89e9..5357232 100644
--- a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/filter/AuthenticationCheckFilter.java
+++ b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/filter/AuthenticationCheckFilter.java
@@ -42,6 +42,7 @@ import javax.servlet.http.HttpSession;
 
 import org.apache.qpid.server.management.plugin.HttpManagementConfiguration;
 import org.apache.qpid.server.management.plugin.HttpManagementUtil;
+import org.apache.qpid.server.security.TokenCarryingPrincipal;
 import org.apache.qpid.server.management.plugin.servlet.ServletConnectionPrincipal;
 import org.apache.qpid.server.model.Broker;
 import org.apache.qpid.server.security.auth.ManagementConnectionPrincipal;
@@ -98,6 +99,9 @@ public class AuthenticationCheckFilter implements Filter
                 else
                 {
                     subject = tryPreemptiveAuthentication(httpRequest);
+
+                    subject.getPrincipals(TokenCarryingPrincipal.class)
+                           .forEach(p -> p.getTokens().forEach(((HttpServletResponse) response)::setHeader));
                     isPreemptiveAuthentication = true;
                 }
             }
diff --git a/doc/java-broker/src/docbkx/security/Java-Broker-Security-Authentication-Providers-Kerberos.xml b/doc/java-broker/src/docbkx/security/Java-Broker-Security-Authentication-Providers-Kerberos.xml
index f710f1b..c69e5b2 100644
--- a/doc/java-broker/src/docbkx/security/Java-Broker-Security-Authentication-Providers-Kerberos.xml
+++ b/doc/java-broker/src/docbkx/security/Java-Broker-Security-Authentication-Providers-Kerberos.xml
@@ -53,7 +53,49 @@ com.sun.security.jgss.accept {
         environment where you are running (see the existing documentation for the C++ broker about
         creating a keytab file). </para>
 
-    <para> Note: You may need to install the "Java Cryptography Extension (JCE) Unlimited Strength
-        Jurisdiction Policy Files" appropriate for your JDK in order to get Kerberos support working. </para>
+    <section xml:id="Java-Broker-Security-Kerberos-Provider-Spnego">
+        <title>SPNEGO Authentication</title>
+        <para>
+            SPNEGO (Simple and Protected GSSAPI Negotiation Mechanism) based authentication can be configured
+            for Web Management Console and REST API.
+        </para>
+        <para>A special JAAS login configuration needs to be provided for
+            Service Principal Name (SPN) <emphasis>HTTP/{FQDN}@REALM</emphasis> in addition to configuration
+            provided for broker service principal in scope <emphasis>com.sun.security.jgss.accept</emphasis>.
+            An example of such SPNEGO configuration is provided below, </para>
+        <programlisting>
+spnego {
+    com.sun.security.auth.module.Krb5LoginModule required
+    useKeyTab=true
+    storeKey=true
+    doNotPrompt=true
+    realm="EXAMPLE.COM"
+    useSubjectCredsOnly=false
+    kdc="kerberos.example.com"
+    keyTab="/path/to/keytab-file-for-HTTP-principal"
+    principal="HTTP/broker.org";
+};</programlisting>
+
+        <important>
+            <para>Please, note that in the example above a principal name is specified as
+            <emphasis>HTTP/broker.org</emphasis> where <emphasis>broker.org</emphasis> is supposed to be
+            a fully qualified name of the host where broker is running. The FQDN used to access the Broker
+            must match the host name in the SPN exactly otherwise the authentication will fail.</para>
+        </important>
+        <para>
+            A name of configuration module in the example above is <emphasis>spnego</emphasis>. It can be
+            communicated to the Kerberos authentication provider via context variable or JVM system property
+            <emphasis>qpid.auth.gssapi.spnegoConfigScope</emphasis>. For example,
+
+    <programlisting>
+        export QPID_OPTS=-Dqpid.auth.gssapi.spnegoConfigScope=spnego -Djavax.security.auth.useSubjectCredsOnly=false -Djava.security.auth.login.config=qpid.conf
+    </programlisting>
+        </para>
+        <para>
+            The RELM part in name of authenticated principal logged with SPNEGO mechanism can be stripped by
+            setting context variable <emphasis>qpid.auth.gssapi.spnegoStripRealmFromPrincipalName</emphasis> to
+            <emphasis>true</emphasis>.
+        </para>
+    </section>
 
 </section>
diff --git a/pom.xml b/pom.xml
index e59d3ab..693b218 100644
--- a/pom.xml
+++ b/pom.xml
@@ -153,6 +153,7 @@
     <maven-surefire-report-plugin-version>2.22.0</maven-surefire-report-plugin-version>
     <h2.version>1.4.199</h2.version>
     <apache-directory-version>2.0.0-M23</apache-directory-version>
+    <kerby-version>1.0.1</kerby-version>
   </properties>
 
   <modules>
@@ -742,6 +743,13 @@
           </exclusion>
         </exclusions>
       </dependency>
+      <!-- kerby test dependency -->
+      <dependency>
+        <groupId>org.apache.kerby</groupId>
+        <artifactId>kerb-simplekdc</artifactId>
+        <scope>test</scope>
+        <version>${kerby-version}</version>
+      </dependency>
     </dependencies>
   </dependencyManagement>
 
diff --git a/qpid-test-utils/src/main/java/org/apache/qpid/test/utils/SystemPropertySetter.java b/qpid-test-utils/src/main/java/org/apache/qpid/test/utils/SystemPropertySetter.java
new file mode 100644
index 0000000..8f9f0d1
--- /dev/null
+++ b/qpid-test-utils/src/main/java/org/apache/qpid/test/utils/SystemPropertySetter.java
@@ -0,0 +1,54 @@
+/*
+ * 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.test.utils;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.rules.ExternalResource;
+
+public class SystemPropertySetter extends ExternalResource
+{
+    private Map<String, String> _storedProperties = new HashMap<>();
+
+    @Override
+    public synchronized void after()
+    {
+        _storedProperties.forEach(this::setProperty);
+    }
+
+    public synchronized void setSystemProperty(final String name, final String value)
+    {
+        _storedProperties.putIfAbsent(name, System.getProperty(name));
+        setProperty(name, value);
+    }
+
+    private void setProperty(final String name, final String value)
+    {
+        if (value == null)
+        {
+            System.clearProperty(name);
+        }
+        else
+        {
+            System.setProperty(name, value);
+        }
+    }
+}
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 752885b..4dcfab0 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
@@ -20,9 +20,7 @@
 
 package org.apache.qpid.test.utils;
 
-import java.util.HashMap;
 import java.util.LinkedHashSet;
-import java.util.Map;
 import java.util.Set;
 
 import com.google.common.base.StandardSystemProperty;
@@ -40,31 +38,17 @@ public class UnitTestBase
     @Rule
     public final TestName _testName = new TestName();
 
-    private final Map<String, String> _propertiesSetForTest = new HashMap<>();
+    @Rule
+    public final SystemPropertySetter _systemPropertySetter = new SystemPropertySetter();
+
     private final Set<Runnable> _tearDownRegistry = new LinkedHashSet<>();
 
     @After
     public void cleanupPostTest()
     {
-        revertSysProps();
-
         _tearDownRegistry.forEach(Runnable::run);
     }
 
-    private void revertSysProps()
-    {
-        _propertiesSetForTest.forEach((key, value) -> {
-            if (value != null)
-            {
-                System.setProperty(key, value);
-            }
-            else
-            {
-                System.clearProperty(key);
-            }
-        });
-    }
-
     public String getTestName()
     {
         return _testName.getMethodName();
@@ -72,19 +56,7 @@ public class UnitTestBase
 
     public void setTestSystemProperty(final String property, final String value)
     {
-        if (!_propertiesSetForTest.containsKey(property))
-        {
-            _propertiesSetForTest.put(property, System.getProperty(property));
-        }
-
-        if (value == null)
-        {
-            System.clearProperty(property);
-        }
-        else
-        {
-            System.setProperty(property, value);
-        }
+        _systemPropertySetter.setSystemProperty(property, value);
     }
 
     public int findFreePort()
@@ -103,7 +75,7 @@ public class UnitTestBase
         _tearDownRegistry.add(runnable);
     }
 
-    public JvmVendor getJvmVendor()
+    public static JvmVendor getJvmVendor()
     {
         final String property = String.valueOf(System.getProperty(StandardSystemProperty.JAVA_VENDOR.key())).toUpperCase();
         if (property.contains("IBM"))


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


[qpid-broker-j] 04/12: QPID-8360: [Broker-J]Add broker and virtual host loggers storing log records in database

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 21c101ae935cb88b7e70b2e20955b14c970ac03f
Author: Alex Rudyy <or...@apache.org>
AuthorDate: Fri Sep 6 15:04:53 2019 +0100

    QPID-8360: [Broker-J]Add broker and virtual host loggers storing log records in database
    
    (cherry picked from commit a33aca40bd224453ad8b0939b2f5af385017b946)
---
 broker-plugins/jdbc-logging-logback/pom.xml        |  95 ++++++++++++
 .../logging/logback/jdbc/JDBCBrokerLogger.java     |  56 +++++++
 .../logging/logback/jdbc/JDBCBrokerLoggerImpl.java | 172 +++++++++++++++++++++
 .../logging/logback/jdbc/JDBCLoggerHelper.java     | 114 ++++++++++++++
 .../logback/jdbc/JDBCSettingsDBNameResolver.java   |  49 ++++++
 .../jdbc/JDBCSettingsDrivenConnectionSource.java   | 110 +++++++++++++
 .../logback/jdbc/JDBCVirtualHostLogger.java}       |  22 ++-
 .../logback/jdbc/JDBCVirtualHostLoggerImpl.java    | 138 +++++++++++++++++
 .../management/logger/brokerlogger/jdbc/add.js     |  41 +++++
 .../management/logger/brokerlogger/jdbc/show.js    |  56 +++++++
 .../logger/virtualhostlogger/jdbc/add.js           |  39 +++++
 .../logger/virtualhostlogger/jdbc/show.js          |  57 +++++++
 .../src/main/java/resources/logger/jdbc/add.html   |  93 +++++++++++
 .../src/main/java/resources/logger/jdbc/show.html  |  38 +++++
 .../logback/jdbc/InMemoryDatabaseTestBase.java     |  65 ++++++++
 .../logback/jdbc/JDBCBrokerLoggerImplTest.java     | 150 ++++++++++++++++++
 .../logging/logback/jdbc/JDBCLoggerHelperTest.java | 114 ++++++++++++++
 .../jdbc/JDBCSettingsDBNameResolverTest.java       |  60 +++++++
 .../JDBCSettingsDrivenConnectionSourceTest.java    | 104 +++++++++++++
 .../jdbc/JDBCVirtualHostLoggerImplTest.java        | 138 +++++++++++++++++
 .../js/qpid/management/store/pool/bonecp/show.js   |   5 +-
 .../qpid/server/store/jdbc/JDBCSettings.java       |   6 +
 .../apache/qpid/server/store/jdbc/JdbcUtils.java   |  36 +++--
 .../qpid/management/store/pool/ConnectionPool.js   | 113 ++++++++++++++
 .../server/logging/logback/AbstractLogger.java     |   7 +-
 .../logging/logback/BrokerFileLoggerImpl.java      |  48 +-----
 .../logback/BrokerLoggerStatusListener.java        |  83 ++++++++++
 ...st.java => BrokerLoggerStatusListenerTest.java} |  16 +-
 .../src/main/java/resources/addLogger.html         |   5 +
 .../java/resources/js/qpid/management/addLogger.js |  27 +++-
 broker/pom.xml                                     |   6 +
 pom.xml                                            |   8 +
 32 files changed, 1996 insertions(+), 75 deletions(-)

diff --git a/broker-plugins/jdbc-logging-logback/pom.xml b/broker-plugins/jdbc-logging-logback/pom.xml
new file mode 100644
index 0000000..cccf84e
--- /dev/null
+++ b/broker-plugins/jdbc-logging-logback/pom.xml
@@ -0,0 +1,95 @@
+<?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/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.qpid</groupId>
+    <artifactId>qpid-broker-parent</artifactId>
+    <version>7.1.5-SNAPSHOT</version>
+    <relativePath>../../pom.xml</relativePath>
+  </parent>
+
+  <artifactId>qpid-broker-plugins-jdbc-logging-logback</artifactId>
+  <name>Apache Qpid Broker-J LogBack JDBC Logging Plug-in</name>
+  <description>LogBack JDBC Logging broker plug-in</description>
+
+  <dependencies>
+
+    <dependency>
+      <groupId>org.apache.qpid</groupId>
+      <artifactId>qpid-broker-plugins-logging-logback</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.qpid</groupId>
+      <artifactId>qpid-broker-plugins-jdbc-store</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.qpid</groupId>
+      <artifactId>qpid-broker-codegen</artifactId>
+      <optional>true</optional>
+    </dependency>
+
+    <!-- test dependencies -->
+    <dependency>
+      <groupId>org.apache.qpid</groupId>
+      <artifactId>qpid-test-utils</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.derby</groupId>
+      <artifactId>derby</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.qpid</groupId>
+      <artifactId>qpid-broker-core</artifactId>
+      <classifier>tests</classifier>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>com.h2database</groupId>
+      <artifactId>h2</artifactId>
+      <version>${h2.version}</version>
+      <scope>test</scope>
+    </dependency>
+
+  </dependencies>
+
+  <build>
+    <resources>
+      <resource>
+        <directory>src/main/resources</directory>
+      </resource>
+      <resource>
+        <directory>src/main/java</directory>
+        <includes>
+          <include>resources/</include>
+        </includes>
+      </resource>
+    </resources>
+  </build>
+
+</project>
diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLogger.java b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLogger.java
new file mode 100644
index 0000000..244b103
--- /dev/null
+++ b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLogger.java
@@ -0,0 +1,56 @@
+/*
+ * 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.logging.logback.jdbc;
+
+import org.apache.qpid.server.model.BrokerLogger;
+import org.apache.qpid.server.model.ManagedAttribute;
+import org.apache.qpid.server.model.ManagedContextDefault;
+import org.apache.qpid.server.store.jdbc.DefaultConnectionProviderFactory;
+import org.apache.qpid.server.store.jdbc.JDBCSettings;
+
+public interface JDBCBrokerLogger<X extends JDBCBrokerLogger<X>> extends BrokerLogger<X>, JDBCSettings
+{
+    String BROKER_FAIL_ON_JDBC_LOGGER_ERROR = "qpid.broker.failOnJdbcLoggerError";
+    @ManagedContextDefault(name = BROKER_FAIL_ON_JDBC_LOGGER_ERROR)
+    @SuppressWarnings("unused")
+    String DEFAULT_BROKER_FAIL_ON_JDBC_LOGGER_ERROR = "false";
+
+    @Override
+    @ManagedAttribute(mandatory=true)
+    String getConnectionUrl();
+
+    @Override
+    @ManagedAttribute(defaultValue= DefaultConnectionProviderFactory.TYPE,
+            validValues = {"org.apache.qpid.server.store.jdbc.DefaultConnectionProviderFactory#getAllAvailableConnectionProviderTypes()"} )
+    String getConnectionPoolType();
+
+    @Override
+    @ManagedAttribute
+    String getUsername();
+
+    @Override
+    @ManagedAttribute(secure=true)
+    String getPassword();
+
+    @Override
+    @ManagedAttribute
+    String getTableNamePrefix();
+
+}
diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLoggerImpl.java b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLoggerImpl.java
new file mode 100644
index 0000000..c371184
--- /dev/null
+++ b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLoggerImpl.java
@@ -0,0 +1,172 @@
+/*
+ * 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.logging.logback.jdbc;
+
+import java.sql.SQLException;
+import java.util.Map;
+import java.util.Set;
+
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.Appender;
+import ch.qos.logback.core.Context;
+import ch.qos.logback.core.status.StatusManager;
+import com.google.common.util.concurrent.ListenableFuture;
+
+import org.apache.qpid.server.logging.logback.AbstractBrokerLogger;
+import org.apache.qpid.server.logging.logback.BrokerLoggerStatusListener;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.ManagedAttributeField;
+import org.apache.qpid.server.model.ManagedObject;
+import org.apache.qpid.server.model.ManagedObjectFactoryConstructor;
+import org.apache.qpid.server.model.SystemConfig;
+import org.apache.qpid.server.store.jdbc.JDBCSettings;
+
+@SuppressWarnings("unused")
+@ManagedObject(category = false, type = JDBCBrokerLoggerImpl.CONFIGURED_OBJECT_TYPE,
+        validChildTypes = "org.apache.qpid.server.logging.logback.AbstractLogger#getSupportedBrokerLoggerChildTypes()")
+public class JDBCBrokerLoggerImpl extends AbstractBrokerLogger<JDBCBrokerLoggerImpl>
+        implements JDBCBrokerLogger<JDBCBrokerLoggerImpl>
+{
+    static final String CONFIGURED_OBJECT_TYPE = "Jdbc";
+    private final JDBCLoggerHelper _jdbcLoggerHelper;
+
+    private volatile BrokerLoggerStatusListener _logbackStatusListener;
+    private volatile StatusManager _statusManager;
+
+    @ManagedAttributeField(afterSet = "restartConnectionSourceIfExists")
+    private String _connectionUrl;
+
+    @ManagedAttributeField(afterSet = "restartConnectionSourceIfExists")
+    private String _connectionPoolType;
+
+    @ManagedAttributeField(afterSet = "restartConnectionSourceIfExists")
+    private String _username;
+
+    @ManagedAttributeField(afterSet = "restartConnectionSourceIfExists")
+    private String _password;
+
+    @ManagedAttributeField(afterSet = "restartAppenderIfExists")
+    private String _tableNamePrefix;
+
+    @ManagedObjectFactoryConstructor
+    protected JDBCBrokerLoggerImpl(final Map<String, Object> attributes, Broker<?> broker)
+    {
+        super(attributes, broker);
+        _jdbcLoggerHelper = new JDBCLoggerHelper();
+    }
+
+    @Override
+    public String getConnectionUrl()
+    {
+        return _connectionUrl;
+    }
+
+    @Override
+    public String getConnectionPoolType()
+    {
+        return _connectionPoolType;
+    }
+
+    @Override
+    public String getUsername()
+    {
+        return _username;
+    }
+
+    @Override
+    public String getPassword()
+    {
+        return _password;
+    }
+
+    @Override
+    public String getTableNamePrefix()
+    {
+        return _tableNamePrefix;
+    }
+
+    @Override
+    protected ListenableFuture<Void> onClose()
+    {
+        onCloseOrDelete();
+        return super.onClose();
+    }
+
+    @Override
+    protected ListenableFuture<Void> onDelete()
+    {
+        onCloseOrDelete();
+        return super.onDelete();
+    }
+
+    @Override
+    protected void validateChange(ConfiguredObject<?> proxyForValidation, Set<String> changedAttributes)
+    {
+        super.validateChange(proxyForValidation, changedAttributes);
+        if (changedAttributes.contains(JDBCSettings.CONNECTION_URL)
+            || changedAttributes.contains(JDBCSettings.USERNAME)
+            || changedAttributes.contains(JDBCSettings.PASSWORD)
+            || changedAttributes.contains(JDBCSettings.CONNECTION_POOL_TYPE))
+        {
+            _jdbcLoggerHelper.validateConnectionSourceSettings(this, (JDBCBrokerLogger) proxyForValidation);
+        }
+    }
+
+    @Override
+    protected void validateOnCreate()
+    {
+        super.validateOnCreate();
+        _jdbcLoggerHelper.validateConnectionSourceSettings(this, this);
+    }
+
+    @Override
+    protected Appender<ILoggingEvent> createAppenderInstance(final Context context)
+    {
+        final SystemConfig<?> systemConfig = getAncestor(SystemConfig.class);
+        _logbackStatusListener = new BrokerLoggerStatusListener(this,
+                                                                systemConfig,
+                                                                BROKER_FAIL_ON_JDBC_LOGGER_ERROR,
+                                                                SQLException.class);
+        _statusManager = context.getStatusManager();
+        _statusManager.add(_logbackStatusListener);
+
+        return _jdbcLoggerHelper.createAppenderInstance(context, this, this);
+    }
+
+    private void onCloseOrDelete()
+    {
+        if (_statusManager != null)
+        {
+            _statusManager.remove(_logbackStatusListener);
+        }
+    }
+
+    private void restartAppenderIfExists()
+    {
+        _jdbcLoggerHelper.restartAppenderIfExists(getAppender());
+    }
+
+    private void restartConnectionSourceIfExists()
+    {
+        _jdbcLoggerHelper.restartConnectionSourceIfExists(getAppender());
+    }
+
+}
diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCLoggerHelper.java b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCLoggerHelper.java
new file mode 100644
index 0000000..d6edd2b
--- /dev/null
+++ b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCLoggerHelper.java
@@ -0,0 +1,114 @@
+/*
+ * 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.logging.logback.jdbc;
+
+import ch.qos.logback.classic.db.DBAppender;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.Appender;
+import ch.qos.logback.core.Context;
+import ch.qos.logback.core.db.ConnectionSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.qpid.server.configuration.IllegalConfigurationException;
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.store.jdbc.JDBCSettings;
+
+class JDBCLoggerHelper
+{
+    private static final Logger LOGGER = LoggerFactory.getLogger(JDBCLoggerHelper.class);
+    final static ch.qos.logback.classic.Logger ROOT_LOGGER =
+            ((ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME));
+
+    Appender<ILoggingEvent> createAppenderInstance(final Context context,
+                                                   final ConfiguredObject<?> logger,
+                                                   final JDBCSettings settings)
+    {
+        try
+        {
+            final JDBCSettingsDBNameResolver dbNameResolver = new JDBCSettingsDBNameResolver(settings);
+            final ConnectionSource connectionSource = createConnectionSource(context, logger, settings);
+            final DBAppender appender = new DBAppender();
+            appender.setDbNameResolver(dbNameResolver);
+            appender.setConnectionSource(connectionSource);
+            appender.setContext(context);
+            appender.start();
+            return appender;
+        }
+        catch (Exception e)
+        {
+            LOGGER.error("Failed to create appender", e);
+            throw new IllegalConfigurationException("Cannot create appender");
+        }
+    }
+
+    void restartAppenderIfExists(final Appender appender)
+    {
+        if (appender != null)
+        {
+            appender.stop();
+            appender.start();
+        }
+    }
+
+    void restartConnectionSourceIfExists(final Appender appender)
+    {
+        if (appender instanceof DBAppender)
+        {
+            final ConnectionSource connectionSource = ((DBAppender) appender).getConnectionSource();
+            if (connectionSource != null)
+            {
+                connectionSource.stop();
+                connectionSource.start();
+            }
+        }
+    }
+
+    void validateConnectionSourceSettings(final ConfiguredObject<?> logger, final JDBCSettings settings)
+    {
+        try
+        {
+            final ConnectionSource connectionSource = createConnectionSource(logger, settings);
+            connectionSource.getConnection().close();
+        }
+        catch (Exception e)
+        {
+            throw new IllegalConfigurationException(
+                    "Cannot create connection source from given URL, credentials and connection pool type");
+        }
+    }
+
+    private ConnectionSource createConnectionSource(final ConfiguredObject<?> logger,
+                                                    final JDBCSettings settings)
+    {
+        return createConnectionSource(ROOT_LOGGER.getLoggerContext(), logger, settings);
+    }
+
+    private ConnectionSource createConnectionSource(final Context context,
+                                                    final ConfiguredObject<?> logger,
+                                                    final JDBCSettings settings)
+    {
+        final JDBCSettingsDrivenConnectionSource connectionSource =
+                new JDBCSettingsDrivenConnectionSource(logger, settings);
+        connectionSource.setContext(context);
+        connectionSource.start();
+        return connectionSource;
+    }
+}
diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDBNameResolver.java b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDBNameResolver.java
new file mode 100644
index 0000000..cc28635
--- /dev/null
+++ b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDBNameResolver.java
@@ -0,0 +1,49 @@
+/*
+ * 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.logging.logback.jdbc;
+
+import ch.qos.logback.classic.db.names.DBNameResolver;
+
+import org.apache.qpid.server.store.jdbc.JDBCSettings;
+
+class JDBCSettingsDBNameResolver implements DBNameResolver
+{
+    private JDBCSettings _settings;
+
+    JDBCSettingsDBNameResolver(final JDBCSettings settings)
+    {
+        _settings = settings;
+    }
+
+    @Override
+    public <N extends Enum<?>> String getTableName(final N tableName)
+    {
+        String settingsTableNamePrefix = _settings.getTableNamePrefix() ;
+        final String prefix = settingsTableNamePrefix == null ? "" : settingsTableNamePrefix;
+        final String name = prefix + tableName.toString();
+        return name.toLowerCase();
+    }
+
+    @Override
+    public <N extends Enum<?>> String getColumnName(final N columnName)
+    {
+        return columnName.toString().toLowerCase();
+    }
+}
diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDrivenConnectionSource.java b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDrivenConnectionSource.java
new file mode 100644
index 0000000..d2f76f6
--- /dev/null
+++ b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDrivenConnectionSource.java
@@ -0,0 +1,110 @@
+/*
+ * 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.logging.logback.jdbc;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.concurrent.atomic.AtomicReference;
+
+import ch.qos.logback.core.db.ConnectionSourceBase;
+import ch.qos.logback.core.db.dialect.SQLDialectCode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.qpid.server.configuration.IllegalConfigurationException;
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.store.jdbc.ConnectionProvider;
+import org.apache.qpid.server.store.jdbc.JDBCSettings;
+import org.apache.qpid.server.store.jdbc.JdbcUtils;
+
+public class JDBCSettingsDrivenConnectionSource extends ConnectionSourceBase
+{
+    private static final Logger LOGGER = LoggerFactory.getLogger(JDBCSettingsDrivenConnectionSource.class);
+
+    private final ConfiguredObject<?> _object;
+    private final JDBCSettings _jdbcSettings;
+    private final AtomicReference<ConnectionProvider> _connectionProvider;
+
+    JDBCSettingsDrivenConnectionSource(final ConfiguredObject<?> object, final JDBCSettings jdbcSettings)
+    {
+        _object = object;
+        _jdbcSettings = jdbcSettings;
+        _connectionProvider = new AtomicReference<>();
+    }
+
+    @Override
+    public Connection getConnection() throws SQLException
+    {
+        final ConnectionProvider connectionProvider = _connectionProvider.get();
+        if (connectionProvider == null)
+        {
+            throw new IllegalConfigurationException("Connection provider does not exist");
+        }
+        return connectionProvider.getConnection();
+    }
+
+    @Override
+    public void start()
+    {
+        _connectionProvider.getAndUpdate(provider -> provider == null ? create() : provider);
+        discoverConnectionProperties();
+        if (!supportsGetGeneratedKeys() && getSQLDialectCode() == SQLDialectCode.UNKNOWN_DIALECT) {
+            addWarn("Connection does not support GetGeneratedKey method and could not discover the dialect.");
+        }
+        super.start();
+    }
+
+    @Override
+    public void stop()
+    {
+        super.stop();
+
+        final ConnectionProvider connectionProvider =  _connectionProvider.getAndSet(null);
+        if (connectionProvider != null)
+        {
+            try
+            {
+                connectionProvider.close();
+            }
+            catch (SQLException e)
+            {
+                LOGGER.warn("Unable to close connection provider", e);
+            }
+        }
+    }
+
+    private ConnectionProvider create()
+    {
+        try
+        {
+            return JdbcUtils.createConnectionProvider(_object, _jdbcSettings, LOGGER);
+        }
+        catch (SQLException e)
+        {
+            throw new IllegalConfigurationException("Cannot create connection provider", e);
+        }
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("JDBCSettingsDrivenConnectionSource{_jdbcSettings=%s}", _jdbcSettings);
+    }
+}
diff --git a/broker-plugins/jdbc-store/src/main/java/org/apache/qpid/server/store/jdbc/JDBCSettings.java b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLogger.java
similarity index 52%
copy from broker-plugins/jdbc-store/src/main/java/org/apache/qpid/server/store/jdbc/JDBCSettings.java
copy to broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLogger.java
index 7efa4ce..76c125b 100644
--- a/broker-plugins/jdbc-store/src/main/java/org/apache/qpid/server/store/jdbc/JDBCSettings.java
+++ b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLogger.java
@@ -17,19 +17,35 @@
  * under the License.
  */
 
-package org.apache.qpid.server.store.jdbc;
+package org.apache.qpid.server.logging.logback.jdbc;
 
-import org.apache.qpid.server.store.Settings;
+import org.apache.qpid.server.model.ManagedAttribute;
+import org.apache.qpid.server.model.ManagedContextDefault;
+import org.apache.qpid.server.model.VirtualHostLogger;
+import org.apache.qpid.server.store.jdbc.DefaultConnectionProviderFactory;
+import org.apache.qpid.server.store.jdbc.JDBCSettings;
 
-public interface JDBCSettings extends Settings
+public interface JDBCVirtualHostLogger<X extends JDBCVirtualHostLogger<X>> extends VirtualHostLogger<X>, JDBCSettings
 {
+    @Override
+    @ManagedAttribute(mandatory=true)
     String getConnectionUrl();
 
+    @Override
+    @ManagedAttribute(defaultValue= DefaultConnectionProviderFactory.TYPE,
+            validValues = {"org.apache.qpid.server.store.jdbc.DefaultConnectionProviderFactory#getAllAvailableConnectionProviderTypes()"} )
     String getConnectionPoolType();
 
+    @Override
+    @ManagedAttribute
     String getUsername();
 
+    @Override
+    @ManagedAttribute(secure=true)
     String getPassword();
 
+    @Override
+    @ManagedAttribute
     String getTableNamePrefix();
+
 }
diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLoggerImpl.java b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLoggerImpl.java
new file mode 100644
index 0000000..2a028f6
--- /dev/null
+++ b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLoggerImpl.java
@@ -0,0 +1,138 @@
+/*
+ * 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.logging.logback.jdbc;
+
+import java.util.Map;
+import java.util.Set;
+
+import ch.qos.logback.classic.db.DBAppender;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.Appender;
+import ch.qos.logback.core.Context;
+import ch.qos.logback.core.status.StatusManager;
+
+import org.apache.qpid.server.logging.logback.AbstractVirtualHostLogger;
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.ManagedAttributeField;
+import org.apache.qpid.server.model.ManagedObject;
+import org.apache.qpid.server.model.ManagedObjectFactoryConstructor;
+import org.apache.qpid.server.model.VirtualHost;
+import org.apache.qpid.server.store.jdbc.JDBCSettings;
+
+@SuppressWarnings("unused")
+@ManagedObject(category = false, type = JDBCVirtualHostLoggerImpl.CONFIGURED_OBJECT_TYPE,
+        validChildTypes = "org.apache.qpid.server.logging.logback.AbstractLogger#getSupportedVirtualHostLoggerChildTypes()")
+public class JDBCVirtualHostLoggerImpl extends AbstractVirtualHostLogger<JDBCVirtualHostLoggerImpl>
+        implements JDBCVirtualHostLogger<JDBCVirtualHostLoggerImpl>
+{
+    static final String CONFIGURED_OBJECT_TYPE = "Jdbc";
+
+    private final JDBCLoggerHelper _jdbcLoggerHelper;
+
+    private StatusManager _statusManager;
+
+    @ManagedAttributeField(afterSet = "restartConnectionSourceIfExists")
+    private String _connectionUrl;
+
+    @ManagedAttributeField(afterSet = "restartConnectionSourceIfExists")
+    private String _connectionPoolType;
+
+    @ManagedAttributeField(afterSet = "restartConnectionSourceIfExists")
+    private String _username;
+
+    @ManagedAttributeField(afterSet = "restartConnectionSourceIfExists")
+    private String _password;
+
+    @ManagedAttributeField(afterSet = "restartAppenderIfExists")
+    private String _tableNamePrefix;
+
+    @ManagedObjectFactoryConstructor
+    protected JDBCVirtualHostLoggerImpl(final Map<String, Object> attributes, VirtualHost<?> virtualHost)
+    {
+        super(attributes, virtualHost);
+        _jdbcLoggerHelper = new JDBCLoggerHelper();
+    }
+
+    @Override
+    public String getConnectionUrl()
+    {
+        return _connectionUrl;
+    }
+
+    @Override
+    public String getConnectionPoolType()
+    {
+        return _connectionPoolType;
+    }
+
+    @Override
+    public String getUsername()
+    {
+        return _username;
+    }
+
+    @Override
+    public String getPassword()
+    {
+        return _password;
+    }
+
+    @Override
+    public String getTableNamePrefix()
+    {
+        return _tableNamePrefix;
+    }
+
+    @Override
+    protected void validateChange(ConfiguredObject<?> proxyForValidation, Set<String> changedAttributes)
+    {
+        super.validateChange(proxyForValidation, changedAttributes);
+        if (changedAttributes.contains(JDBCSettings.CONNECTION_URL)
+            || changedAttributes.contains(JDBCSettings.USERNAME)
+            || changedAttributes.contains(JDBCSettings.PASSWORD)
+            || changedAttributes.contains(JDBCSettings.CONNECTION_POOL_TYPE))
+        {
+            _jdbcLoggerHelper.validateConnectionSourceSettings(this, (JDBCVirtualHostLogger) proxyForValidation);
+        }
+    }
+
+    @Override
+    protected void validateOnCreate()
+    {
+        super.validateOnCreate();
+        _jdbcLoggerHelper.validateConnectionSourceSettings(this, this);
+    }
+
+    @Override
+    protected Appender<ILoggingEvent> createAppenderInstance(final Context context)
+    {
+        return _jdbcLoggerHelper.createAppenderInstance(context, this, this);
+    }
+
+    private void restartAppenderIfExists()
+    {
+        _jdbcLoggerHelper.restartAppenderIfExists(getAppender());
+    }
+
+    private void restartConnectionSourceIfExists()
+    {
+        _jdbcLoggerHelper.restartConnectionSourceIfExists(getAppender());
+    }
+}
diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/resources/js/qpid/management/logger/brokerlogger/jdbc/add.js b/broker-plugins/jdbc-logging-logback/src/main/java/resources/js/qpid/management/logger/brokerlogger/jdbc/add.js
new file mode 100644
index 0000000..91a40d5
--- /dev/null
+++ b/broker-plugins/jdbc-logging-logback/src/main/java/resources/js/qpid/management/logger/brokerlogger/jdbc/add.js
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+define(["dojo/dom-construct",
+        "qpid/common/util",
+        "dojo/parser",
+        "dojo/text!logger/jdbc/add.html",
+        "qpid/management/store/pool/ConnectionPool",
+        "dojo/domReady!"],
+    function (domConstruct, util, parser, template, ConnectionPool) {
+
+    return {
+        show: function (data) {
+            var that = this;
+            if (data.hasOwnProperty("containerNode"))
+            {
+                var containerNode = domConstruct.create("div", {innerHTML: template}, data.containerNode);
+                parser.parse(containerNode)
+                    .then(function () {
+                        ConnectionPool.initPoolFieldsInDialog("addLogger", data);
+                        util.applyToWidgets(data.containerNode, data.category, data.type, data.data, data.metadata);
+                    });
+            }
+        }
+    };
+});
diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/resources/js/qpid/management/logger/brokerlogger/jdbc/show.js b/broker-plugins/jdbc-logging-logback/src/main/java/resources/js/qpid/management/logger/brokerlogger/jdbc/show.js
new file mode 100644
index 0000000..d8973cb
--- /dev/null
+++ b/broker-plugins/jdbc-logging-logback/src/main/java/resources/js/qpid/management/logger/brokerlogger/jdbc/show.js
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+define(["qpid/common/util",
+        "dojo/query",
+        "dojo/text!logger/jdbc/show.html",
+        "qpid/management/store/pool/ConnectionPool",
+        "dojo/domReady!"], function (util, query, template, ConnectionPool) {
+    function BrokerJdbcLogger(params)
+    {
+        var that = this;
+        if (template && params.hasOwnProperty("containerNode"))
+        {
+            util.parse(params.containerNode, template, function () {
+                if (params.hasOwnProperty("metadata"))
+                {
+                    that.attributeContainers =
+                        util.collectAttributeNodes(params.containerNode, params.metadata, "BrokerLogger", "Jdbc");
+                    var container = query(".connectionPoolTypeAttributeContainer", params.containerNode)[0];
+                    that.poolSettings = new ConnectionPool(container, params.management, params.modelObj);
+
+                    if (params.hasOwnProperty("data"))
+                    {
+                        that.update(params.data);
+                    }
+                }
+
+            });
+        }
+    }
+
+    BrokerJdbcLogger.prototype.update = function (data) {
+        util.updateAttributeNodes(this.attributeContainers, data);
+        if (this.poolSettings)
+        {
+            this.poolSettings.update(data);
+        }
+    };
+
+    return BrokerJdbcLogger;
+});
diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/resources/js/qpid/management/logger/virtualhostlogger/jdbc/add.js b/broker-plugins/jdbc-logging-logback/src/main/java/resources/js/qpid/management/logger/virtualhostlogger/jdbc/add.js
new file mode 100644
index 0000000..435d780
--- /dev/null
+++ b/broker-plugins/jdbc-logging-logback/src/main/java/resources/js/qpid/management/logger/virtualhostlogger/jdbc/add.js
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+define(["dojo/dom-construct",
+        "qpid/common/util",
+        "dojo/parser",
+        "dojo/text!logger/jdbc/add.html",
+        "qpid/management/store/pool/ConnectionPool",
+        "dojo/domReady!"], function (domConstruct, util, parser, template, ConnectionPool) {
+    return {
+        show: function (data) {
+            var that = this;
+            if (data.hasOwnProperty("containerNode"))
+            {
+                var containerNode = domConstruct.create("div", {innerHTML: template}, data.containerNode);
+                parser.parse(containerNode)
+                    .then(function () {
+                        ConnectionPool.initPoolFieldsInDialog("addLogger", data);
+                        util.applyToWidgets(data.containerNode, data.category, data.type, data.data, data.metadata);
+                    });
+            }
+        }
+    };
+});
diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/resources/js/qpid/management/logger/virtualhostlogger/jdbc/show.js b/broker-plugins/jdbc-logging-logback/src/main/java/resources/js/qpid/management/logger/virtualhostlogger/jdbc/show.js
new file mode 100644
index 0000000..69dbda3
--- /dev/null
+++ b/broker-plugins/jdbc-logging-logback/src/main/java/resources/js/qpid/management/logger/virtualhostlogger/jdbc/show.js
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+define(["qpid/common/util",
+        "dojo/query",
+        "dojo/text!logger/jdbc/show.html",
+        "qpid/management/store/pool/ConnectionPool",
+        "dojo/domReady!"], function (util, query, template, ConnectionPool) {
+
+    function VirtualHostJdbcLogger(params)
+    {
+        var that = this;
+        if (template && params.hasOwnProperty("containerNode"))
+        {
+            util.parse(params.containerNode, template, function () {
+                if (params.hasOwnProperty("metadata"))
+                {
+                    that.attributeContainers =
+                        util.collectAttributeNodes(params.containerNode, params.metadata, "VirtualHostLogger", "Jdbc");
+                    var container = query(".connectionPoolTypeAttributeContainer", params.containerNode)[0];
+                    that.poolSettings = new ConnectionPool(container, params.management, params.modelObj);
+
+                    if (params.hasOwnProperty("data"))
+                    {
+                        that.update(params.data);
+                    }
+                }
+
+            });
+        }
+    }
+
+    VirtualHostJdbcLogger.prototype.update = function (data) {
+        util.updateAttributeNodes(this.attributeContainers, data);
+        if (this.poolSettings)
+        {
+            this.poolSettings.update(data);
+        }
+    };
+
+    return VirtualHostJdbcLogger;
+});
diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/resources/logger/jdbc/add.html b/broker-plugins/jdbc-logging-logback/src/main/java/resources/logger/jdbc/add.html
new file mode 100644
index 0000000..f4fe5d4
--- /dev/null
+++ b/broker-plugins/jdbc-logging-logback/src/main/java/resources/logger/jdbc/add.html
@@ -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.
+  -->
+
+<div>
+    <div class="formBox clear">
+        <fieldset>
+            <legend>JDBC Settings</legend>
+            <div class="clear">
+                <div class="formLabel-labelCell tableContainer-labelCell">JDBC Url*:</div>
+                <div class="formLabel-controlCell tableContainer-valueCell">
+                    <input type="text" id="addLogger.connectionUrl"
+                           data-dojo-type="dijit/form/ValidationTextBox"
+                           data-dojo-props="
+                                      name: 'connectionUrl',
+                                      placeHolder: 'jdbc:provider:info',
+                                      required: true,
+                                      missingMessage: 'JDBC URL must be supplied',
+                                      title: 'Enter JDBC URL'"/>
+                </div>
+            </div>
+            <div class="clear">
+                <div class="formLabel-labelCell tableContainer-labelCell">Username*:</div>
+                <div class="formLabel-controlCell tableContainer-valueCell">
+                    <input type="text" id="addLogger.username"
+                           data-dojo-type="dijit/form/ValidationTextBox"
+                           data-dojo-props="
+                                      name: 'username',
+                                      placeHolder: 'username',
+                                      required: true,
+                                      missingMessage: 'Username must be supplied',
+                                      title: 'Enter username'" />
+                </div>
+            </div>
+            <div class="clear">
+                <div class="formLabel-labelCell tableContainer-labelCell">Password*:</div>
+                <div class="formLabel-controlCell tableContainer-valueCell">
+                    <input type="password" id="addLogger.password"
+                           data-dojo-type="dijit/form/ValidationTextBox"
+                           data-dojo-props="
+                                      name: 'password',
+                                      placeHolder: 'password',
+                                      missingMessage: 'Password must be supplied',
+                                      title: 'Enter password'" />
+                </div>
+            </div>
+            <div class="clear">
+                <div class="formLabel-labelCell tableContainer-labelCell">Connection Pool*:</div>
+                <div class="formLabel-controlCell tableContainer-valueCell">
+                    <input type="text" id="addLogger.connectionPoolType"
+                           data-dojo-type="dijit/form/FilteringSelect"
+                           data-dojo-props="
+                                      name: 'connectionPoolType',
+                                      required: true,
+                                      missingMessage: 'Connection Pool type must be supplied',
+                                      title: 'Select Connection Pool',
+                                      placeHolder: 'Select pool type'" />
+                </div>
+            </div>
+            <div class="clear">
+                <div class="formLabel-labelCell tableContainer-labelCell">Table name prefix:</div>
+                <div class="formLabel-controlCell tableContainer-valueCell">
+                    <input type="text" id="addLogger.tableNamePrefix"
+                           data-dojo-type="dijit/form/ValidationTextBox"
+                           data-dojo-props="
+                              name: 'tableNamePrefix',
+                              placeHolder: 'table name prefix',
+                              required: false,
+                              regExp: '[a-zA-Z_0-9]*',
+                              promptMessage: 'Optional database table prefix so multiple loggers can share the same database',
+                              title: 'Optional database table prefix so multiple loggers can share the same database'" />
+                </div>
+            </div>
+            <div class="clear"></div>
+            <div id="addLogger.poolSpecificDiv"></div>
+        </fieldset>
+    </div>
+</div>
diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/resources/logger/jdbc/show.html b/broker-plugins/jdbc-logging-logback/src/main/java/resources/logger/jdbc/show.html
new file mode 100644
index 0000000..026b155
--- /dev/null
+++ b/broker-plugins/jdbc-logging-logback/src/main/java/resources/logger/jdbc/show.html
@@ -0,0 +1,38 @@
+<!--
+  ~ 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.
+  -->
+<div>
+    <div class="clear">
+        <div class="formLabel-labelCell">Connection URL:</div>
+        <div class="connectionUrl"></div>
+    </div>
+    <div class="clear usernameAttributeContainer">
+        <div class="formLabel-labelCell">Username:</div>
+        <div class="username"></div>
+    </div>
+    <div class="clear">
+        <div class="formLabel-labelCell">Connection Pool Type:</div>
+        <div class="connectionPoolType"></div>
+    </div>
+    <div class="clear">
+        <div class="formLabel-labelCell">Table Name Prefix:</div>
+        <div class="tableNamePrefix"></div>
+    </div>
+    <div class="clear connectionPoolTypeAttributeContainer"></div>
+    <div class="clear"></div>
+</div>
diff --git a/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/InMemoryDatabaseTestBase.java b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/InMemoryDatabaseTestBase.java
new file mode 100644
index 0000000..8af8e83
--- /dev/null
+++ b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/InMemoryDatabaseTestBase.java
@@ -0,0 +1,65 @@
+/*
+ * 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.logging.logback.jdbc;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import org.junit.After;
+import org.junit.Before;
+
+import org.apache.qpid.test.utils.UnitTestBase;
+
+public class InMemoryDatabaseTestBase extends UnitTestBase
+{
+    private Connection _setupConnection;
+
+    @Before
+    public  void startUpDatabase() throws SQLException
+    {
+        _setupConnection = DriverManager.getConnection(getTestDatabaseUrl());
+    }
+
+    @After
+    public void shutDownDatabase() throws SQLException
+    {
+        try (final Statement statement = _setupConnection.createStatement())
+        {
+            statement.execute("DROP ALL OBJECTS");
+        }
+        finally
+        {
+            _setupConnection.close();
+        }
+    }
+
+    String getTestDatabaseUrl()
+    {
+        return String.format("jdbc:h2:mem:%s", getTestName());
+    }
+
+    protected Connection getConnection()
+    {
+        return _setupConnection;
+    }
+
+}
diff --git a/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLoggerImplTest.java b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLoggerImplTest.java
new file mode 100644
index 0000000..48740ec
--- /dev/null
+++ b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLoggerImplTest.java
@@ -0,0 +1,150 @@
+/*
+ * 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.logging.logback.jdbc;
+
+import static org.apache.qpid.server.logging.logback.jdbc.JDBCLoggerHelper.ROOT_LOGGER;
+import static org.apache.qpid.server.logging.logback.jdbc.JDBCLoggerHelperTest.INVALID_JDBC_URL;
+import static org.apache.qpid.server.model.BrokerTestHelper.createBrokerMock;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import ch.qos.logback.classic.db.DBAppender;
+import ch.qos.logback.core.Appender;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.qpid.server.configuration.IllegalConfigurationException;
+import org.apache.qpid.server.store.jdbc.JDBCSettings;
+
+public class JDBCBrokerLoggerImplTest extends InMemoryDatabaseTestBase
+{
+    private static final String TABLE_PREFIX = "broker_";
+
+    private JDBCBrokerLoggerImpl _logger;
+
+    @Before
+    public void setUp()
+    {
+        final Map<String, Object> attributes = new HashMap<>();
+        attributes.put(JDBCBrokerLoggerImpl.NAME, getTestName());
+        attributes.put(JDBCSettings.CONNECTION_URL, getTestDatabaseUrl());
+        _logger = new JDBCBrokerLoggerImpl(attributes, createBrokerMock());
+    }
+
+    @After
+    public void tearDown()
+    {
+        if (_logger != null)
+        {
+            _logger.close();
+        }
+    }
+
+    @Test
+    public void createAppenderOnCreate()
+    {
+        _logger.create();
+        final Appender appender = ROOT_LOGGER.getAppender(getTestName());
+        assertTrue(appender instanceof DBAppender);
+    }
+
+    @Test
+    public void createAppenderOnOpen()
+    {
+        _logger.open();
+        final Appender appender = ROOT_LOGGER.getAppender(getTestName());
+        assertTrue(appender instanceof DBAppender);
+    }
+
+    @Test
+    public void closeAndReopenLogger()
+    {
+        _logger.create();
+        _logger.close();
+        final Appender appender = ROOT_LOGGER.getAppender(getTestName());
+        assertNotNull(appender);
+        _logger.open();
+        assertSame(appender, ROOT_LOGGER.getAppender(getTestName()));
+    }
+
+    @Test
+    public void detachAppenderInstanceOnDelete()
+    {
+        _logger.create();
+        _logger.delete();
+        final Appender appender = ROOT_LOGGER.getAppender(getTestName());
+        assertNull(appender);
+    }
+
+    @Test
+    public void createLoggerWithInvalidURL()
+    {
+        final Map<String, Object> attributes = new HashMap<>();
+        attributes.put(JDBCBrokerLoggerImpl.NAME, getTestName());
+        attributes.put(JDBCSettings.CONNECTION_URL, INVALID_JDBC_URL);
+        final JDBCBrokerLoggerImpl logger = new JDBCBrokerLoggerImpl(attributes, createBrokerMock());
+        try
+        {
+            logger.create();
+            fail("Exception should be thrown");
+        }
+        catch (IllegalConfigurationException e)
+        {
+            // pass
+        }
+    }
+
+    @Test
+    public void changeLoggerURLtoInvalid()
+    {
+        _logger.create();
+        final Map<String, Object> attributes = Collections.singletonMap(JDBCSettings.CONNECTION_URL, INVALID_JDBC_URL);
+        try
+        {
+            _logger.setAttributes(attributes);
+            fail("Exception should be thrown");
+        }
+        catch (IllegalConfigurationException e)
+        {
+            // pass
+        }
+    }
+
+    @Test
+    public void changeTablePrefix()
+    {
+        _logger.create();
+
+        final Map<String, Object> attributes = Collections.singletonMap(JDBCSettings.TABLE_NAME_PREFIX, TABLE_PREFIX);
+        _logger.setAttributes(attributes);
+
+        assertEquals(TABLE_PREFIX, _logger.getTableNamePrefix());
+    }
+
+}
diff --git a/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCLoggerHelperTest.java b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCLoggerHelperTest.java
new file mode 100644
index 0000000..0e03e47
--- /dev/null
+++ b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCLoggerHelperTest.java
@@ -0,0 +1,114 @@
+/*
+ * 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.logging.logback.jdbc;
+
+import static org.apache.qpid.server.logging.logback.jdbc.JDBCLoggerHelper.ROOT_LOGGER;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.db.DBAppender;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.Appender;
+import ch.qos.logback.core.db.ConnectionSource;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.qpid.server.configuration.IllegalConfigurationException;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.BrokerTestHelper;
+import org.apache.qpid.server.store.jdbc.JDBCSettings;
+
+public class JDBCLoggerHelperTest extends InMemoryDatabaseTestBase
+{
+    static final String INVALID_JDBC_URL = "jdbc:invalid";
+    private JDBCSettings _jdbcSettings;
+    private JDBCLoggerHelper _jdbcLoggerHelper;
+    private Broker<?> _broker;
+
+    @Before
+    public void setUp()
+    {
+        _jdbcSettings = mock(JDBCSettings.class);
+        when(_jdbcSettings.getConnectionUrl()).thenReturn(getTestDatabaseUrl());
+        _jdbcLoggerHelper = new JDBCLoggerHelper();
+        _broker = BrokerTestHelper.createBrokerMock();
+    }
+
+    @Test
+    public void createAppenderInstance()
+    {
+        final LoggerContext context = ROOT_LOGGER.getLoggerContext();
+        final Appender<ILoggingEvent> appender =
+                _jdbcLoggerHelper.createAppenderInstance(context, _broker, _jdbcSettings);
+        assertTrue(appender instanceof DBAppender);
+        assertTrue(appender.isStarted());
+        assertEquals(context, appender.getContext());
+        assertTrue(((DBAppender)appender).getConnectionSource() instanceof JDBCSettingsDrivenConnectionSource);
+    }
+
+    @Test
+    public void restartAppenderIfExists()
+    {
+        final Appender appender = mock(Appender.class);
+        _jdbcLoggerHelper.restartAppenderIfExists(appender);
+        verify(appender).stop();
+        verify(appender).start();
+        verifyNoMoreInteractions(appender);
+    }
+
+    @Test
+    public void restartConnectionSourceIfExists()
+    {
+        final ConnectionSource connectionSource = mock(ConnectionSource.class);
+        final DBAppender appender = mock(DBAppender.class);
+        when(appender.getConnectionSource()).thenReturn(connectionSource);
+        _jdbcLoggerHelper.restartConnectionSourceIfExists(appender);
+        verify(connectionSource).stop();
+        verify(connectionSource).start();
+        verifyNoMoreInteractions(connectionSource);
+    }
+
+    @Test
+    public void validateConnectionSourceSettings()
+    {
+        _jdbcLoggerHelper.validateConnectionSourceSettings(_broker, _jdbcSettings);
+    }
+
+    @Test
+    public void validateConnectionSourceSettingsForInvalidURL()
+    {
+        when(_jdbcSettings.getConnectionUrl()).thenReturn(INVALID_JDBC_URL);
+        try
+        {
+            _jdbcLoggerHelper.validateConnectionSourceSettings(_broker, _jdbcSettings);
+            fail("Exception is expected");
+        }
+        catch (IllegalConfigurationException e)
+        {
+            // pass
+        }
+    }
+}
diff --git a/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDBNameResolverTest.java b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDBNameResolverTest.java
new file mode 100644
index 0000000..4da137f
--- /dev/null
+++ b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDBNameResolverTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.logging.logback.jdbc;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import ch.qos.logback.classic.db.names.ColumnName;
+import ch.qos.logback.classic.db.names.TableName;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.qpid.server.store.jdbc.JDBCSettings;
+import org.apache.qpid.test.utils.UnitTestBase;
+
+public class JDBCSettingsDBNameResolverTest extends UnitTestBase
+{
+    private static final String TABLE_PREFIX = "test_";
+    private JDBCSettingsDBNameResolver _dbNameResolver;
+
+    @Before
+    public void setUp()
+    {
+        final JDBCSettings jdbcSettings = mock(JDBCSettings.class);
+        when(jdbcSettings.getTableNamePrefix()).thenReturn(TABLE_PREFIX);
+        _dbNameResolver = new JDBCSettingsDBNameResolver(jdbcSettings);
+    }
+
+    @Test
+    public void getTableName()
+    {
+        assertEquals((TABLE_PREFIX + TableName.LOGGING_EVENT.name()).toLowerCase(),
+                     _dbNameResolver.getTableName(TableName.LOGGING_EVENT));
+    }
+
+    @Test
+    public void getColumnName()
+    {
+        assertEquals(ColumnName.LOGGER_NAME.name().toLowerCase(),
+                     _dbNameResolver.getColumnName(ColumnName.LOGGER_NAME));
+    }
+}
diff --git a/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDrivenConnectionSourceTest.java b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDrivenConnectionSourceTest.java
new file mode 100644
index 0000000..0120452
--- /dev/null
+++ b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDrivenConnectionSourceTest.java
@@ -0,0 +1,104 @@
+/*
+ * 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.logging.logback.jdbc;
+
+import static org.apache.qpid.server.logging.logback.jdbc.JDBCLoggerHelper.ROOT_LOGGER;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.qpid.server.configuration.IllegalConfigurationException;
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.store.jdbc.JDBCSettings;
+
+public class JDBCSettingsDrivenConnectionSourceTest extends InMemoryDatabaseTestBase
+{
+    private JDBCSettingsDrivenConnectionSource _connectionSource;
+
+    @Before
+    public void setUp()
+    {
+        final JDBCSettings jdbcSettings = mock(JDBCSettings.class);
+        when(jdbcSettings.getConnectionUrl()).thenReturn( getTestDatabaseUrl());
+
+        final ConfiguredObject<?> object = mock(ConfiguredObject.class);
+        _connectionSource = new JDBCSettingsDrivenConnectionSource(object, jdbcSettings);
+        _connectionSource.setContext(ROOT_LOGGER.getLoggerContext());
+    }
+
+    @After
+    public void tearDown()
+    {
+        if (_connectionSource != null)
+        {
+            _connectionSource.stop();
+        }
+    }
+
+    @Test
+    public void testStart() throws SQLException
+    {
+        try
+        {
+            _connectionSource.getConnection();
+            fail("connection should fail for non started ConnectionSource");
+        }
+        catch (IllegalConfigurationException e)
+        {
+            // pass
+        }
+
+        _connectionSource.start();
+
+        final Connection connection = _connectionSource.getConnection();
+        connection.close();
+    }
+
+    @Test
+    public void testStop() throws SQLException
+    {
+        _connectionSource.start();
+        _connectionSource.stop();
+        try
+        {
+            _connectionSource.getConnection();
+            fail("connection should fail for stopped ConnectionSource");
+        }
+        catch (IllegalConfigurationException e)
+        {
+            // pass
+        }
+    }
+
+    @Test
+    public void testGetConnection() throws SQLException
+    {
+        _connectionSource.start();
+        final Connection connection = _connectionSource.getConnection();
+        connection.close();
+    }
+}
diff --git a/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLoggerImplTest.java b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLoggerImplTest.java
new file mode 100644
index 0000000..ce3b00c
--- /dev/null
+++ b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLoggerImplTest.java
@@ -0,0 +1,138 @@
+/*
+ * 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.logging.logback.jdbc;
+
+import static org.apache.qpid.server.logging.logback.jdbc.JDBCLoggerHelper.ROOT_LOGGER;
+import static org.apache.qpid.server.model.BrokerTestHelper.createBrokerMock;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import ch.qos.logback.classic.db.DBAppender;
+import ch.qos.logback.core.Appender;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.qpid.server.configuration.IllegalConfigurationException;
+import org.apache.qpid.server.model.BrokerTestHelper;
+import org.apache.qpid.server.store.jdbc.JDBCSettings;
+
+public class JDBCVirtualHostLoggerImplTest extends InMemoryDatabaseTestBase
+{
+    private static final String TABLE_PREFIX = "vh_";
+
+    private JDBCVirtualHostLoggerImpl _logger;
+
+    @Before
+    public void setUp() throws Exception
+    {
+        final Map<String, Object> attributes = new HashMap<>();
+        attributes.put(JDBCVirtualHostLoggerImpl.NAME, getTestName());
+        attributes.put(JDBCSettings.CONNECTION_URL, getTestDatabaseUrl());
+        _logger = new JDBCVirtualHostLoggerImpl(attributes, BrokerTestHelper.createVirtualHost(getTestName(), this));
+    }
+
+    @After
+    public void tearDown()
+    {
+        if (_logger != null)
+        {
+            _logger.close();
+        }
+    }
+
+    @Test
+    public void createAppenderOnCreate()
+    {
+        _logger.create();
+        final Appender appender = ROOT_LOGGER.getAppender(getTestName());
+        assertTrue(appender instanceof DBAppender);
+    }
+
+    @Test
+    public void createAppenderOnOpen()
+    {
+        _logger.open();
+        final Appender appender = ROOT_LOGGER.getAppender(getTestName());
+        assertTrue(appender instanceof DBAppender);
+    }
+
+    @Test
+    public void detachAppenderInstanceOnDelete()
+    {
+        _logger.create();
+        _logger.delete();
+        final Appender appender = ROOT_LOGGER.getAppender(getTestName());
+        assertNull(appender);
+    }
+
+    @Test
+    public void createLoggerWithInvalidURL()
+    {
+        final Map<String, Object> attributes = new HashMap<>();
+        attributes.put(JDBCBrokerLoggerImpl.NAME, getTestName());
+        attributes.put(JDBCSettings.CONNECTION_URL, JDBCLoggerHelperTest.INVALID_JDBC_URL);
+        final JDBCBrokerLoggerImpl logger = new JDBCBrokerLoggerImpl(attributes, createBrokerMock());
+        try
+        {
+            logger.create();
+            fail("Exception should be thrown");
+        }
+        catch (IllegalConfigurationException e)
+        {
+            // pass
+        }
+    }
+
+    @Test
+    public void changeLoggerURLtoInvalid()
+    {
+        _logger.create();
+        final Map<String, Object> attributes = Collections.singletonMap(JDBCSettings.CONNECTION_URL,
+                                                                        JDBCLoggerHelperTest.INVALID_JDBC_URL);
+        try
+        {
+            _logger.setAttributes(attributes);
+            fail("Exception should be thrown");
+        }
+        catch (IllegalConfigurationException e)
+        {
+            // pass
+        }
+    }
+
+    @Test
+    public void changeTablePrefix()
+    {
+        _logger.create();
+
+        final Map<String, Object> attributes = Collections.singletonMap(JDBCSettings.TABLE_NAME_PREFIX, TABLE_PREFIX);
+        _logger.setAttributes(attributes);
+
+        assertEquals(TABLE_PREFIX, _logger.getTableNamePrefix());
+    }
+
+}
diff --git a/broker-plugins/jdbc-provider-bone/src/main/java/resources/js/qpid/management/store/pool/bonecp/show.js b/broker-plugins/jdbc-provider-bone/src/main/java/resources/js/qpid/management/store/pool/bonecp/show.js
index 0297165..9cc166a 100644
--- a/broker-plugins/jdbc-provider-bone/src/main/java/resources/js/qpid/management/store/pool/bonecp/show.js
+++ b/broker-plugins/jdbc-provider-bone/src/main/java/resources/js/qpid/management/store/pool/bonecp/show.js
@@ -26,7 +26,8 @@ define(["dojo/_base/xhr", "dojo/parser", "dojox/html/entities", "dojo/query", "d
         function BoneCP(data)
         {
             var containerNode = data.containerNode;
-            this.parent = data.parent;
+            this.management = data.management ? data.management : data.parent.management;
+            this.modelObj = data.modelObj ? data.modelObj : data.parent.modelObj;
             var that = this;
             xhr.get({
                 url: "store/pool/bonecp/show.html",
@@ -57,7 +58,7 @@ define(["dojo/_base/xhr", "dojo/parser", "dojox/html/entities", "dojo/query", "d
 
         BoneCP.prototype._update = function (data)
         {
-            this.parent.management.load(this.parent.modelObj,
+            this.management.load(this.modelObj,
                 {
                     excludeInheritedContext: false,
                     depth: 0
diff --git a/broker-plugins/jdbc-store/src/main/java/org/apache/qpid/server/store/jdbc/JDBCSettings.java b/broker-plugins/jdbc-store/src/main/java/org/apache/qpid/server/store/jdbc/JDBCSettings.java
index 7efa4ce..01ee196 100644
--- a/broker-plugins/jdbc-store/src/main/java/org/apache/qpid/server/store/jdbc/JDBCSettings.java
+++ b/broker-plugins/jdbc-store/src/main/java/org/apache/qpid/server/store/jdbc/JDBCSettings.java
@@ -23,6 +23,12 @@ import org.apache.qpid.server.store.Settings;
 
 public interface JDBCSettings extends Settings
 {
+    String CONNECTION_URL = "connectionUrl";
+    String CONNECTION_POOL_TYPE = "connectionPoolType";
+    String USERNAME = "username";
+    String PASSWORD = "password";
+    String TABLE_NAME_PREFIX = "tableNamePrefix";
+
     String getConnectionUrl();
 
     String getConnectionPoolType();
diff --git a/broker-plugins/jdbc-store/src/main/java/org/apache/qpid/server/store/jdbc/JdbcUtils.java b/broker-plugins/jdbc-store/src/main/java/org/apache/qpid/server/store/jdbc/JdbcUtils.java
index d3df9ae..a23b362 100644
--- a/broker-plugins/jdbc-store/src/main/java/org/apache/qpid/server/store/jdbc/JdbcUtils.java
+++ b/broker-plugins/jdbc-store/src/main/java/org/apache/qpid/server/store/jdbc/JdbcUtils.java
@@ -80,9 +80,11 @@ public class JdbcUtils
 
     }
 
-    static ConnectionProvider createConnectionProvider(final ConfiguredObject<?> parent, final Logger logger)
+    public static ConnectionProvider createConnectionProvider(final ConfiguredObject<?> parent,
+                                                              final JDBCSettings settings,
+                                                              final Logger logger)
+            throws SQLException
     {
-        JDBCSettings settings = (JDBCSettings) parent;
         String connectionPoolType = settings.getConnectionPoolType() == null
                 ? DefaultConnectionProviderFactory.TYPE
                 : settings.getConnectionPoolType();
@@ -95,20 +97,26 @@ public class JdbcUtils
             connectionProviderFactory = new DefaultConnectionProviderFactory();
         }
 
-        try
+        Map<String, String> providerAttributes = new HashMap<>();
+        Set<String> providerAttributeNames = new HashSet<>(connectionProviderFactory.getProviderAttributeNames());
+        providerAttributeNames.retainAll(parent.getContextKeys(false));
+        for (String attr : providerAttributeNames)
         {
-            Map<String, String> providerAttributes = new HashMap<>();
-            Set<String> providerAttributeNames = new HashSet<>(connectionProviderFactory.getProviderAttributeNames());
-            providerAttributeNames.retainAll(parent.getContextKeys(false));
-            for (String attr : providerAttributeNames)
-            {
-                providerAttributes.put(attr, parent.getContextValue(String.class, attr));
-            }
+            providerAttributes.put(attr, parent.getContextValue(String.class, attr));
+        }
 
-            return connectionProviderFactory.getConnectionProvider(settings.getConnectionUrl(),
-                                                                   settings.getUsername(),
-                                                                   settings.getPassword(),
-                                                                   providerAttributes);
+        return connectionProviderFactory.getConnectionProvider(settings.getConnectionUrl(),
+                                                               settings.getUsername(),
+                                                               settings.getPassword(),
+                                                               providerAttributes);
+    }
+
+    static ConnectionProvider createConnectionProvider(final ConfiguredObject<?> parent, final Logger logger)
+    {
+        JDBCSettings settings = (JDBCSettings) parent;
+        try
+        {
+            return createConnectionProvider(parent, settings, logger);
         }
         catch (SQLException e)
         {
diff --git a/broker-plugins/jdbc-store/src/main/java/resources/js/qpid/management/store/pool/ConnectionPool.js b/broker-plugins/jdbc-store/src/main/java/resources/js/qpid/management/store/pool/ConnectionPool.js
new file mode 100644
index 0000000..79b9ee2
--- /dev/null
+++ b/broker-plugins/jdbc-store/src/main/java/resources/js/qpid/management/store/pool/ConnectionPool.js
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+define(["qpid/common/util",
+        "dijit/registry",
+        "dojo/_base/array",
+        "dojo/dom-construct",
+        "dojo/dom",
+        "dojo/string"],
+    function (util, registry, array, domConstruct, dom, string) {
+
+        function ConnectionPool(container, management, modelObj)
+        {
+            this.containerNode = container;
+            this.previousConnectionPoolType = null;
+            this.management = management;
+            this.modelObj = modelObj;
+            this.poolDetails = null;
+        }
+
+        ConnectionPool.prototype.update = function (data) {
+            if (data && data.hasOwnProperty("connectionPoolType")
+                && (!this.poolDetails || this.previousConnectionPoolType !== data.connectionPoolType))
+            {
+                var that = this;
+                require(["qpid/management/store/pool/" + data.connectionPoolType.toLowerCase() + "/show"],
+                    function (PoolDetails) {
+                        that.poolDetails = that._createPoolDetails(PoolDetails);
+                        that.previousConnectionPoolType = data.connectionPoolType;
+                        that.poolDetails.update(data);
+                    });
+            }
+            else
+            {
+                this.poolDetails.update(data);
+            }
+        };
+
+        ConnectionPool.prototype._createPoolDetails = function (PoolDetails) {
+            var widgets = registry.findWidgets(this.containerNode);
+            array.forEach(widgets, function (item) {
+                item.destroyRecursive();
+            });
+            domConstruct.empty(this.containerNode);
+
+            return new PoolDetails({
+                containerNode: this.containerNode,
+                management: this.management,
+                modelObj: this.modelObj
+            });
+        };
+
+        ConnectionPool.initPoolFieldsInDialog = function (dialogIdPrefix, data) {
+            registry.byId(dialogIdPrefix + ".connectionUrl")
+                .set("regExpGen", util.jdbcUrlOrContextVarRegexp);
+            registry.byId(dialogIdPrefix + ".username")
+                .set("regExpGen", util.nameOrContextVarRegexp);
+
+            var passwordControl = registry.byId(dialogIdPrefix + ".password");
+            passwordControl.set("required", !data.data);
+
+            var poolTypeControl = registry.byId(dialogIdPrefix + ".connectionPoolType");
+
+            var typeMetaData = data.metadata.getMetaData(data.category, data.type);
+            var values = ["NONE"];
+            if (typeMetaData.attributes.hasOwnProperty("connectionPoolType")
+                && typeMetaData.attributes.connectionPoolType.hasOwnProperty("validValues"))
+            {
+                values = typeMetaData.attributes.connectionPoolType.validValues;
+            }
+            var store = util.makeTypeStore(values);
+            poolTypeControl.set("store", store);
+            poolTypeControl.set("value", "NONE");
+
+            var poolTypeFieldsDiv = dom.byId(dialogIdPrefix + ".poolSpecificDiv");
+            poolTypeControl.on("change", function (type) {
+                if (type && string.trim(type) !== "")
+                {
+                    var widgets = registry.findWidgets(poolTypeFieldsDiv);
+                    array.forEach(widgets, function (item) {
+                        item.destroyRecursive();
+                    });
+                    widgets.forEach(function (item) {
+                        item.destroyRecursive();
+                    });
+                    domConstruct.empty(poolTypeFieldsDiv);
+                    require(["qpid/management/store/pool/" + type.toLowerCase() + "/add"], function (poolType) {
+                        poolType.show({
+                            containerNode: poolTypeFieldsDiv,
+                            context: data.context
+                        });
+                    });
+                }
+            });
+        };
+        return ConnectionPool;
+    });
diff --git a/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/AbstractLogger.java b/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/AbstractLogger.java
index 90296da..071309e 100644
--- a/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/AbstractLogger.java
+++ b/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/AbstractLogger.java
@@ -127,7 +127,7 @@ public abstract class AbstractLogger<X extends AbstractLogger<X>> extends Abstra
 
     public void stopLogging()
     {
-        Appender appender = ROOT_LOGGER.getAppender(getName());
+        final Appender appender = getAppender();
         if (appender != null)
         {
             appender.stop();
@@ -135,6 +135,11 @@ public abstract class AbstractLogger<X extends AbstractLogger<X>> extends Abstra
         }
     }
 
+    protected Appender<ILoggingEvent> getAppender()
+    {
+        return ROOT_LOGGER.getAppender(getName());
+    }
+
     private class LogInclusionRuleListener extends AbstractConfigurationChangeListener
     {
 
diff --git a/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/BrokerFileLoggerImpl.java b/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/BrokerFileLoggerImpl.java
index a6a4031..0338e38 100644
--- a/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/BrokerFileLoggerImpl.java
+++ b/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/BrokerFileLoggerImpl.java
@@ -34,16 +34,12 @@ import ch.qos.logback.classic.spi.ILoggingEvent;
 import ch.qos.logback.core.Appender;
 import ch.qos.logback.core.Context;
 import ch.qos.logback.core.rolling.RollingFileAppender;
-import ch.qos.logback.core.status.Status;
 import ch.qos.logback.core.status.StatusListener;
 import ch.qos.logback.core.status.StatusManager;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import org.apache.qpid.server.logging.LogFileDetails;
-import org.apache.qpid.server.logging.messages.BrokerMessages;
 import org.apache.qpid.server.model.Broker;
 import org.apache.qpid.server.model.ConfiguredObject;
 import org.apache.qpid.server.model.Content;
@@ -56,8 +52,6 @@ import org.apache.qpid.server.util.DaemonThreadFactory;
 public class BrokerFileLoggerImpl extends AbstractBrokerLogger<BrokerFileLoggerImpl>
         implements BrokerFileLogger<BrokerFileLoggerImpl>, FileLoggerSettings
 {
-    private static final Logger LOGGER = LoggerFactory.getLogger(BrokerFileLoggerImpl.class);
-
     private volatile RolloverWatcher _rolloverWatcher;
     private ScheduledExecutorService _rolledPolicyExecutor;
 
@@ -200,7 +194,11 @@ public class BrokerFileLoggerImpl extends AbstractBrokerLogger<BrokerFileLoggerI
     protected Appender<ILoggingEvent> createAppenderInstance(Context loggerContext)
     {
         SystemConfig<?> systemConfig = getAncestor(SystemConfig.class);
-        _logbackStatusListener = new BrokerFileLoggerStatusListener(this, systemConfig);
+        _logbackStatusListener = new BrokerLoggerStatusListener(this,
+                                                                systemConfig,
+                                                                BROKER_FAIL_ON_LOGGER_IO_ERROR,
+                                                                IOException.class,
+                                                                IOError.class);
         _statusManager = loggerContext.getStatusManager();
         _statusManager.add(_logbackStatusListener);
 
@@ -232,41 +230,5 @@ public class BrokerFileLoggerImpl extends AbstractBrokerLogger<BrokerFileLoggerI
         }
     }
 
-    static class BrokerFileLoggerStatusListener implements StatusListener
-    {
-        private final SystemConfig<?> _systemConfig;
-        private final BrokerFileLogger<?> _brokerFileLogger;
-
-        public BrokerFileLoggerStatusListener(BrokerFileLogger<?> brokerFileLogger, SystemConfig<?> systemConfig)
-        {
-            _brokerFileLogger = brokerFileLogger;
-            _systemConfig = systemConfig;
-        }
-
-        @Override
-        public void addStatusEvent(Status status)
-        {
-            Throwable throwable = status.getThrowable();
-            if (status.getEffectiveLevel() == Status.ERROR
-                    && (throwable instanceof IOException || throwable instanceof IOError))
-            {
-                LOGGER.error("Unexpected I/O error whilst trying to write to log file. Log messages could be lost.", throwable);
-                if (_brokerFileLogger.getContextValue(Boolean.class, BROKER_FAIL_ON_LOGGER_IO_ERROR))
-                {
-                    try
-                    {
-                        _brokerFileLogger.stopLogging();
-                        _systemConfig.getEventLogger().message(BrokerMessages.FATAL_ERROR(
-                                String.format("Shutting down the broker because context variable '%s' is set and unexpected i/o issue occurred: %s",
-                                        BROKER_FAIL_ON_LOGGER_IO_ERROR, throwable.getMessage())));
-                    }
-                    finally
-                    {
-                        _systemConfig.closeAsync();
-                    }
-                }
-            }
-        }
-    }
 
 }
diff --git a/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/BrokerLoggerStatusListener.java b/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/BrokerLoggerStatusListener.java
new file mode 100644
index 0000000..7497953
--- /dev/null
+++ b/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/BrokerLoggerStatusListener.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.qpid.server.logging.logback;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import ch.qos.logback.core.status.Status;
+import ch.qos.logback.core.status.StatusListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.qpid.server.logging.messages.BrokerMessages;
+import org.apache.qpid.server.model.BrokerLogger;
+import org.apache.qpid.server.model.SystemConfig;
+
+public class BrokerLoggerStatusListener implements StatusListener
+{
+    private static final Logger LOGGER = LoggerFactory.getLogger(BrokerLoggerStatusListener.class);
+
+    private final SystemConfig<?> _systemConfig;
+    private final BrokerLogger<?> _brokerLogger;
+    private final String _contextFlag;
+    private final Set<Class<?>> _errorClasses;
+
+    public BrokerLoggerStatusListener(final BrokerLogger<?> brokerLogger,
+                               final SystemConfig<?> systemConfig,
+                               final String contextFlag,
+                               final Class<?>... errorClass)
+    {
+        _brokerLogger = brokerLogger;
+        _systemConfig = systemConfig;
+        _contextFlag = contextFlag;
+        _errorClasses =
+                errorClass == null ? Collections.emptySet() : Arrays.stream(errorClass).collect(Collectors.toSet());
+    }
+
+    @Override
+    public void addStatusEvent(Status status)
+    {
+        Throwable throwable = status.getThrowable();
+        if (status.getEffectiveLevel() == Status.ERROR
+            && _errorClasses.stream().anyMatch(c -> c.isInstance(throwable)))
+        {
+            LOGGER.error("Unexpected error whilst trying to store log entry. Log messages could be lost.", throwable);
+            if (_brokerLogger.getContextValue(Boolean.class, _contextFlag))
+            {
+                try
+                {
+                    _brokerLogger.stopLogging();
+                    _systemConfig.getEventLogger().message(BrokerMessages.FATAL_ERROR(
+                            String.format(
+                                    "Shutting down the broker because context variable '%s' is set and unexpected logging issue occurred: %s",
+                                    _contextFlag,
+                                    throwable.getMessage())));
+                }
+                finally
+                {
+                    _systemConfig.closeAsync();
+                }
+            }
+        }
+    }
+}
diff --git a/broker-plugins/logging-logback/src/test/java/org/apache/qpid/server/logging/logback/BrokerFileLoggerStatusListenerTest.java b/broker-plugins/logging-logback/src/test/java/org/apache/qpid/server/logging/logback/BrokerLoggerStatusListenerTest.java
similarity index 87%
rename from broker-plugins/logging-logback/src/test/java/org/apache/qpid/server/logging/logback/BrokerFileLoggerStatusListenerTest.java
rename to broker-plugins/logging-logback/src/test/java/org/apache/qpid/server/logging/logback/BrokerLoggerStatusListenerTest.java
index 6645fcb..7cd0329 100644
--- a/broker-plugins/logging-logback/src/test/java/org/apache/qpid/server/logging/logback/BrokerFileLoggerStatusListenerTest.java
+++ b/broker-plugins/logging-logback/src/test/java/org/apache/qpid/server/logging/logback/BrokerLoggerStatusListenerTest.java
@@ -37,9 +37,9 @@ import org.apache.qpid.server.logging.EventLogger;
 import org.apache.qpid.server.model.SystemConfig;
 import org.apache.qpid.test.utils.UnitTestBase;
 
-public class BrokerFileLoggerStatusListenerTest extends UnitTestBase
+public class BrokerLoggerStatusListenerTest extends UnitTestBase
 {
-    private BrokerFileLoggerImpl.BrokerFileLoggerStatusListener _statusListener;
+    private BrokerLoggerStatusListener _statusListener;
     private BrokerFileLogger<?> _fileLogger;
     private SystemConfig<?> _systemConfig;
 
@@ -50,12 +50,12 @@ public class BrokerFileLoggerStatusListenerTest extends UnitTestBase
         _systemConfig = mock(SystemConfig.class);
         EventLogger eventLogger = mock(EventLogger.class);
         when(_systemConfig.getEventLogger()).thenReturn(eventLogger);
-        _statusListener = new BrokerFileLoggerImpl.BrokerFileLoggerStatusListener(_fileLogger, _systemConfig);
+        _statusListener = new BrokerLoggerStatusListener(_fileLogger, _systemConfig, BrokerFileLogger.BROKER_FAIL_ON_LOGGER_IO_ERROR, IOException.class, IOError.class);
         when(_fileLogger.getContextValue(Boolean.class, BrokerFileLogger.BROKER_FAIL_ON_LOGGER_IO_ERROR)).thenReturn(true);
     }
 
     @Test
-    public void testAddStatusEventForIOError() throws Exception
+    public void testAddStatusEventForIOError()
     {
         Status event = createEvent(new IOError(new IOException("Mocked: No disk space left")), Status.ERROR);
         _statusListener.addStatusEvent(event);
@@ -64,7 +64,7 @@ public class BrokerFileLoggerStatusListenerTest extends UnitTestBase
     }
 
     @Test
-    public void testAddStatusEventForIOErrorWithFailOnLoggerIOErrorDisabled() throws Exception
+    public void testAddStatusEventForIOErrorWithFailOnLoggerIOErrorDisabled()
     {
         Status event = createEvent(new IOError(new IOException("Mocked: No disk space left")), Status.ERROR);
         when(_fileLogger.getContextValue(Boolean.class, BrokerFileLogger.BROKER_FAIL_ON_LOGGER_IO_ERROR)).thenReturn(false);
@@ -74,7 +74,7 @@ public class BrokerFileLoggerStatusListenerTest extends UnitTestBase
     }
 
     @Test
-    public void testAddStatusEventForIOException() throws Exception
+    public void testAddStatusEventForIOException()
     {
         Status event = createEvent(new IOException("Mocked: No disk space left"), Status.ERROR);
         _statusListener.addStatusEvent(event);
@@ -83,7 +83,7 @@ public class BrokerFileLoggerStatusListenerTest extends UnitTestBase
     }
 
     @Test
-    public void testAddStatusEventForIOExceptionReportedAsWarning() throws Exception
+    public void testAddStatusEventForIOExceptionReportedAsWarning()
     {
         Status event = createEvent(new IOException("Mocked: No disk space left"), Status.WARN);
         _statusListener.addStatusEvent(event);
@@ -92,7 +92,7 @@ public class BrokerFileLoggerStatusListenerTest extends UnitTestBase
     }
 
     @Test
-    public void testAddStatusEventForNonIOException() throws Exception
+    public void testAddStatusEventForNonIOException()
     {
         Status event = createEvent(new RuntimeException("Mocked: No disk space left"), Status.ERROR);
         _statusListener.addStatusEvent(event);
diff --git a/broker-plugins/management-http/src/main/java/resources/addLogger.html b/broker-plugins/management-http/src/main/java/resources/addLogger.html
index 04f70de..c0aa6b5 100644
--- a/broker-plugins/management-http/src/main/java/resources/addLogger.html
+++ b/broker-plugins/management-http/src/main/java/resources/addLogger.html
@@ -69,6 +69,11 @@
                     <div id="addLogger.typeFields"></div>
                 </div>
                 <div class="clear"></div>
+                <div data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'Context variables',  open: false">
+                    <div id="addLogger.context"
+                         data-dojo-type="qpid.common.ContextVariablesEditor"
+                         data-dojo-props="name: 'context', title: 'Context variables'"></div>
+                </div>
             </div>
             <div class="dijitDialogPaneActionBar qpidDialogPaneActionBar">
                 <button data-dojo-type="dijit/form/Button" id="addLogger.addButton" data-dojo-props="label: 'Save'" type="submit"></button>
diff --git a/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addLogger.js b/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addLogger.js
index 44ac1d2..9c368ae 100644
--- a/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addLogger.js
+++ b/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addLogger.js
@@ -30,6 +30,7 @@ define(["dojo/_base/lang",
         'dojo/json',
         "qpid/common/util",
         "dojo/text!addLogger.html",
+        "qpid/common/ContextVariablesEditor",
         "dojo/store/Memory",
         "dojox/validate/us",
         "dojox/validate/web",
@@ -92,6 +93,7 @@ define(["dojo/_base/lang",
 
                 this.categoryFieldsContainer = dom.byId("addLogger.categoryFields");
                 this.allFieldsContainer = dom.byId("addLogger.contentPane");
+                this.context = registry.byId("addLogger.context");
             },
             show: function (management, modelObj, category, actualData)
             {
@@ -119,12 +121,18 @@ define(["dojo/_base/lang",
                 var virtualHostlLoggerEditWarningNode = dom.byId("virtualHostlLoggerEditWarning");
                 domStyle.set(brokerLoggerEditWarningNode,
                     "display",
-                    !this.isNew && this.category == "BrokerLogger" ? "block" : "none");
+                    !this.isNew && this.category === "BrokerLogger" ? "block" : "none");
                 domStyle.set(virtualHostlLoggerEditWarningNode,
                     "display",
-                    !this.isNew && this.category == "VirtualHostLogger" ? "block" : "none");
+                    !this.isNew && this.category === "VirtualHostLogger" ? "block" : "none");
 
-                this._loadCategoryUserInterfacesAndShowDialog(actualData);
+                util.loadEffectiveAndInheritedActualData(this.management, this.modelObj, lang.hitch(this, function(data)
+                {
+                    this.context.setData(this.isNew ? {} : this.initialData.context ,
+                        data.effective.context,
+                        data.inheritedActual.context);
+                    this._loadCategoryUserInterfacesAndShowDialog(actualData);
+                }));
             },
             hide: function ()
             {
@@ -150,6 +158,16 @@ define(["dojo/_base/lang",
                                        || this.management.metadata.getDefaultValueForType(this.category,
                             this.loggerType.get("value"));
                     var formData = util.getFormWidgetValues(this.form, excludedData);
+                    var context = this.context.get("value");
+                    var oldContext = null;
+                    if (this.initialData !== null && this.initialData !== undefined)
+                    {
+                        oldContext = this.initialData.context;
+                    }
+                    if (context && !util.equals(context, oldContext))
+                    {
+                        formData["context"] = context;
+                    }
                     var that = this;
                     if (this.isNew)
                     {
@@ -200,7 +218,8 @@ define(["dojo/_base/lang",
                                 data: that.initialData,
                                 metadata: that.management.metadata,
                                 category: that.category,
-                                type: type
+                                type: type,
+                                context: that.context
                             });
                             if (promise)
                             {
diff --git a/broker/pom.xml b/broker/pom.xml
index f271102..b00fcbd 100644
--- a/broker/pom.xml
+++ b/broker/pom.xml
@@ -111,6 +111,12 @@
 
     <dependency>
       <groupId>org.apache.qpid</groupId>
+      <artifactId>qpid-broker-plugins-jdbc-logging-logback</artifactId>
+      <scope>runtime</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.qpid</groupId>
       <artifactId>qpid-broker-plugins-amqp-1-0-protocol-jdbc-link-store</artifactId>
       <scope>runtime</scope>
     </dependency>
diff --git a/pom.xml b/pom.xml
index 88a5748..7e034e7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -151,6 +151,7 @@
     <buildnumber-maven-plugin-version>1.4</buildnumber-maven-plugin-version>
     <maven-jar-plugin-version>3.1.0</maven-jar-plugin-version>
     <maven-surefire-report-plugin-version>2.22.0</maven-surefire-report-plugin-version>
+    <h2.version>1.4.199</h2.version>
   </properties>
 
   <modules>
@@ -168,6 +169,7 @@
     <module>broker-plugins/derby-store</module>
     <module>broker-plugins/jdbc-provider-bone</module>
     <module>broker-plugins/jdbc-store</module>
+    <module>broker-plugins/jdbc-logging-logback</module>
     <module>broker-plugins/logging-logback</module>
     <module>broker-plugins/management-amqp</module>
     <module>broker-plugins/management-http</module>
@@ -347,6 +349,12 @@
 
       <dependency>
         <groupId>org.apache.qpid</groupId>
+        <artifactId>qpid-broker-plugins-jdbc-logging-logback</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+
+      <dependency>
+        <groupId>org.apache.qpid</groupId>
         <artifactId>qpid-broker-plugins-memory-store</artifactId>
         <version>${project.version}</version>
       </dependency>


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


[qpid-broker-j] 02/12: QPID-8354: [Broker-J] Blacklist TLSv1.1

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 d3b0a88a1de792917e230b94b50b44b45f72c18d
Author: Tomas Vavricka <to...@deutsche-boerse.com>
AuthorDate: Thu Sep 19 15:33:14 2019 +0200

    QPID-8354: [Broker-J] Blacklist TLSv1.1
    
    (cherry picked from commit 84125e51c445bef4070d88ae11a85f859b8ef667)
---
 .../server/configuration/CommonProperties.java     |   4 +-
 .../java/org/apache/qpid/server/model/Broker.java  |   6 +-
 .../server/transport/TCPandSSLTransportTest.java   | 161 ++++++++++++---------
 3 files changed, 102 insertions(+), 69 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 949216d..600f985 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
@@ -40,7 +40,7 @@ import org.slf4j.LoggerFactory;
 /**
  * Centralised record of Qpid common properties.
  *
- * Qpid build specific information like  project name, version number, and source code repository revision number
+ * Qpid build specific information like project name, version number, and source code repository revision number
  * are captured by this class and exposed via public static methods.
  *
  */
@@ -57,7 +57,7 @@ public class CommonProperties
     public static final String QPID_SECURITY_TLS_PROTOCOL_WHITE_LIST = "qpid.security.tls.protocolWhiteList";
     public static final String QPID_SECURITY_TLS_PROTOCOL_WHITE_LIST_DEFAULT = "TLSv1\\.[0-9]+";
     public static final String QPID_SECURITY_TLS_PROTOCOL_BLACK_LIST = "qpid.security.tls.protocolBlackList";
-    public static final String QPID_SECURITY_TLS_PROTOCOL_BLACK_LIST_DEFAULT = "TLSv1\\.0";
+    public static final String QPID_SECURITY_TLS_PROTOCOL_BLACK_LIST_DEFAULT = "TLSv1\\.[0-1]";
 
     public static final String QPID_SECURITY_TLS_CIPHER_SUITE_WHITE_LIST = "qpid.security.tls.cipherSuiteWhiteList";
     public static final String QPID_SECURITY_TLS_CIPHER_SUITE_WHITE_LIST_DEFAULT = "";
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 e959818..62e2519 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
@@ -107,10 +107,12 @@ public interface Broker<X extends Broker<X>> extends ConfiguredObject<X>, EventL
     boolean DEFAULT_BROKER_MSG_AUTH = false;
 
     @ManagedContextDefault(name = CommonProperties.QPID_SECURITY_TLS_PROTOCOL_WHITE_LIST)
-    String DEFAULT_SECURITY_TLS_PROTOCOL_WHITE_LIST = "[\"TLSv1\\\\.[0-9]+\"]";
+    String DEFAULT_SECURITY_TLS_PROTOCOL_WHITE_LIST =
+            "[\"" + CommonProperties.QPID_SECURITY_TLS_PROTOCOL_WHITE_LIST_DEFAULT.replace("\\", "\\\\") + "\"]";
 
     @ManagedContextDefault(name = CommonProperties.QPID_SECURITY_TLS_PROTOCOL_BLACK_LIST)
-    String DEFAULT_SECURITY_TLS_PROTOCOL_BLACK_LIST = "[\"TLSv1\\\\.0\"]";
+    String DEFAULT_SECURITY_TLS_PROTOCOL_BLACK_LIST =
+            "[\"" + CommonProperties.QPID_SECURITY_TLS_PROTOCOL_BLACK_LIST_DEFAULT.replace("\\", "\\\\") + "\"]";
 
     @ManagedContextDefault(name = CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_WHITE_LIST)
     String DEFAULT_SECURITY_TLS_CIPHER_SUITE_WHITE_LIST = "[]";
diff --git a/broker-core/src/test/java/org/apache/qpid/server/transport/TCPandSSLTransportTest.java b/broker-core/src/test/java/org/apache/qpid/server/transport/TCPandSSLTransportTest.java
index ef6d5f4..c3ce9f3 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/transport/TCPandSSLTransportTest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/transport/TCPandSSLTransportTest.java
@@ -62,6 +62,48 @@ public class TCPandSSLTransportTest extends UnitTestBase
 {
     private static final Logger LOGGER = LoggerFactory.getLogger(TCPandSSLTransportTest.class);
 
+    /** self signed cert keystore valid until Oct 2024 */
+    private static final String KEYSTORE_STRING =
+            "/u3+7QAAAAIAAAABAAAAAQAKc2VsZnNpZ25lZAAAAUkYmo+uAAAFATCCBP0wDgYKKwYBBAEqAhEB"
+            + "AQUABIIE6bR+b7FHo2BRT/WG+zDIfO8zOXoGIbuNL2znNMnvEp9xwfMQOkhKxEbVtX8uJ7HSwi1V"
+            + "bV2it0CA59sgvRt9awmgg+W1CLgkGKNOB+kQZbjL8R8lXmKibw4yU/EFm5rqDqPEXBRBj40TF0aT"
+            + "GtCCmmLPsH2pGU1wH2Ne/tozk8q7hYK6XMH/i43ZXhS9V2CKzPWrzhXmvjFKCtmYHNLj5nLLE/n0"
+            + "snqAssBoFSAJKmqkqHQBJNQjm4oqJFSISB8pwDX++0kvOMM7j5ryjVwihsCYuHZ6lh5BntDGF41L"
+            + "f4XADfv3Fma6nZQKfKs0VU2kAWUmjPpyV1FFq/ua4x6SUdZKS22YIQ3t6iO76TDABbQNyUX+Ge4n"
+            + "k6clF8MFswKTT0ug7zjb17d36gwl+UznvFqMSE6Zkrr9nNAcSVlQS+JaazXveiVEXTBYCAZgsNw3"
+            + "3KqlLWliAegnwQCQLOguw7bgusnZ/E61/TL8GTryiwN1mltbnsWkCjMj1AGUBM3sYNwbj87Vdhij"
+            + "iHJbjcB7q3Dak68khrCTLmqoD43KHBB5g+UMlruXYbE0elWqYpXGjI5cvt4gzfh1V+ira5DOfa4B"
+            + "Qskv/dh1uj2xAe1YEvF3xmdO2F6Yuzd88VO0aaPGroYPfRmh2M6rEOlwc2Ku/p23FjSWrLyzori8"
+            + "8/OKV4PM2b/NtY51ztTKWR/eUdX6qTPUJMK5CJiOxKGxk9PDtmsbQY685H6QVDKzTkbaPlP97+Oa"
+            + "xv3/2RIWR7KJzsxbqiYhX0fevRJw/RY6ZY3NEE5RAmCjzxD+1qDtu0QM/LspgPxyv5oSInAtT23U"
+            + "BrcNIiQ8jO+6E+fDcVhFSrs6gLGe1BwKYHsosjvup8FETLZgqKY6g1mwECA/Un2agzhI4tGC0O8v"
+            + "lU4VEZKrXwgy/XQ5C2vwwgLvJh94OfE20Wuf7Jjq8IUPcdF201XeYREE/vSNcBnJf22yPouJMIPk"
+            + "yNxlAHcapeFUi00yC19FEIpdoW/8pX2k64jx63CwwVckWWOIWlg8N+z9jsiwdjvm5wL2aFU3+wtu"
+            + "8Nj6Soy7Y3QYAwx17q/nUOJOk5DqLedG+/DKXVs5jghmbQ9wyzqGjGs+xYvSCXtQJygETUU/ddoM"
+            + "/iK4hhnZL2uqZ0wamef4ibdBbhpoRO8C7mSbi7TbDtcfysZrMb6i5MugR+NwKKzN2DznXItvpgzc"
+            + "Xm9j7LP8HZcQANa+1o2aIGDqK1fMSAOmBbTWlYkHPDbpoE/lx32iBNL/Aj8aKbtkwy/J2JRvo9m2"
+            + "uBdLK4DoDeTjqG//AwISrwm9y6xxIIPNQq7GiftN6p9KCI87U5pxqs5yUQ1g/e9DCioLe8O3Vug7"
+            + "+1jS1ZHWFtb4BBEF3EhkKa1AOVKNu9+M8lcG9tKWUBjnIFTD68a++6B36ShRnIZNbmbRkLC6wWdB"
+            + "SdyI6FWPxsPvGSF+3wq+n+0bu75N3Xsta5tEOjc67DfnQlyZtP/BIZsKxgEueOcXkjzaXMPYcrlJ"
+            + "2BInovQSHnSHvQfaBKqj/nKcGaDyydfdxF5fyjRPFYF+fFCWXrFkbQgAst8ymJ//UpLomfw+Ni6f"
+            + "xx2XQGt3941zhRuXJI2tdvUb2Czzsp0tq+h46d0WOlYQ57Q70weUQRrtARqCKoSp/gNUzQsvd+FO"
+            + "sUUxKRoJltRYBwAAAAEABVguNTA5AAADdTCCA3EwggJZoAMCAQICBBAXeI4wDQYJKoZIhvcNAQEL"
+            + "BQAwaDELMAkGA1UEBhMCVUsxETAPBgNVBAgTCFNjb3RsYW5kMRAwDgYDVQQHEwdHbGFzZ293MQ8w"
+            + "DQYDVQQKEwZBcGFjaGUxDTALBgNVBAsTBFFwaWQxFDASBgNVBAMTC0FwYWNoZSBRcGlkMCAXDTE0"
+            + "MTAxNjEwNTY1NVoYDzIxMTMwNTEwMTA1NjU1WjBoMQswCQYDVQQGEwJVSzERMA8GA1UECBMIU2Nv"
+            + "dGxhbmQxEDAOBgNVBAcTB0dsYXNnb3cxDzANBgNVBAoTBkFwYWNoZTENMAsGA1UECxMEUXBpZDEU"
+            + "MBIGA1UEAxMLQXBhY2hlIFFwaWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC520Yd"
+            + "1GuXh67h7HawvL5/pwTr46P45R0gx+LDGC1Equ9/wvvsVbCPL0JLDTSKl0qpgbJNMH/A740vSilb"
+            + "FDdqfyOuIkQZN1Ub9CkOaI5uR9RjaC2MfyNUJl7Gp64nSYk9iDX15ddZjsAijUDvET32XzfirlML"
+            + "dwLXv1Y5dLskV0r6xK4NdLtXi+Ndn+Uy4EllD7VMIFaLt6oG9Vo6mNl0jze7Yz/aYYtWns4x+uG8"
+            + "WbMgtcXo/VxCyp+4ji06XFerwfkS0zBS1wfvxd5Qb1+4dYovSn1v0AaPvZ0XwG4XErP2/svU01nc"
+            + "C43Z4neHdsj8Y/kmXLDD8Nc7Mpv/Wm6hAgMBAAGjITAfMB0GA1UdDgQWBBQfKBRPr/QD7PjpM3s4"
+            + "rD8u6ZxiijANBgkqhkiG9w0BAQsFAAOCAQEAFjyjJ8pbHf6MioZpOOlZh4lz6F+9dW1KyJR0OIc4"
+            + "FXnYnU/CNzjkwPminuZJoYgXBh+sVFN238YFS3I8ONEQJy8uSH33T81sklXhqnrSk9OlWk1v60wH"
+            + "NwwNFz5ZuGrGlvk9EFhbC8FgdkXJbz21drAl18i2oJHPdQQNwdc6mwqhpNfjqZ2opfJPbVscX1P/"
+            + "dbJjfcoZ01fy5687zjpN11G4egwsrya2FZiAw1WPI10OhrJgiGL5aDiDLjauNZmoM7QchUUD1cjE"
+            + "EwvRkU1MesliLg4y3UqDoV6ooHB4ClE2aKmIdbVB/eP1QrEEkey93ptt1z5fLk1l408AkXQtzyw7"
+            + "9WC+xnZta0IoYC/vO29IVsok";
     @Test
     public void testNoSSLv3SupportOnSSLOnlyPort() throws Exception
     {
@@ -77,14 +119,14 @@ public class TCPandSSLTransportTest extends UnitTestBase
         }
     }
 
-
     @Test
-    public void testNoTLSv1SupportOnSharedPort() throws Exception
+    public void testNoSSLv3SupportOnSharedPort() throws Exception
     {
+        assumeThat("The IBM JDK has different TLS defaults", getJvmVendor(), is(not(equalTo(IBM))));
         try
         {
-            checkSSLExcluded("TLSv1", Transport.TCP, Transport.SSL);
-            fail("Should not be able to connect using TLSv1");
+            checkSSLExcluded("SSLv3", Transport.TCP, Transport.SSL);
+            fail("Should not be able to connect using SSLv3");
         }
         catch(SSLHandshakeException e)
         {
@@ -92,7 +134,6 @@ public class TCPandSSLTransportTest extends UnitTestBase
         }
     }
 
-
     @Test
     public void testNoTLSv1SupportOnSSLOnlyPort() throws Exception
     {
@@ -107,15 +148,13 @@ public class TCPandSSLTransportTest extends UnitTestBase
         }
     }
 
-
     @Test
-    public void testNoSSLv3SupportOnSharedPort() throws Exception
+    public void testNoTLSv1SupportOnSharedPort() throws Exception
     {
-        assumeThat("The IBM JDK has different TLS defaults", getJvmVendor(), is(not(equalTo(IBM))));
         try
         {
-            checkSSLExcluded("SSLv3", Transport.TCP, Transport.SSL);
-            fail("Should not be able to connect using SSLv3");
+            checkSSLExcluded("TLSv1", Transport.TCP, Transport.SSL);
+            fail("Should not be able to connect using TLSv1");
         }
         catch(SSLHandshakeException e)
         {
@@ -123,28 +162,67 @@ public class TCPandSSLTransportTest extends UnitTestBase
         }
     }
 
+    @Test
+    public void testNoTLSv1_1SupportOnSSLOnlyPort() throws Exception
+    {
+        try
+        {
+            checkSSLExcluded("TLSv1.1", Transport.SSL);
+            fail("Should not be able to connect using TLSv1.1");
+        }
+        catch(SSLHandshakeException e)
+        {
+            // pass
+        }
+    }
 
     @Test
-    public void testTLSSupportOnSharedPort() throws Exception
+    public void testNoTLSv1_1SupportOnSharedPort() throws Exception
     {
         try
         {
             checkSSLExcluded("TLSv1.1", Transport.TCP, Transport.SSL);
+            fail("Should not be able to connect using TLSv1.1");
         }
         catch(SSLHandshakeException e)
         {
-            LOGGER.error("Should be able to connect using TLSv1.1", e);
-            fail("Should be able to connect using TLSv1.1");
+            // pass
         }
     }
 
+    @Test
+    public void testTLSv1_2SupportOnSSLOnlyPort() throws Exception
+    {
+        try
+        {
+            checkSSLExcluded("TLSv1.2", Transport.SSL);
+        }
+        catch(SSLHandshakeException e)
+        {
+            LOGGER.error("Should be able to connect using TLSv1.2", e);
+            fail("Should be able to connect using TLSv1.2");
+        }
+    }
+
+    @Test
+    public void testTLSv1_2SupportOnSharedPort() throws Exception
+    {
+        try
+        {
+            checkSSLExcluded("TLSv1.2", Transport.TCP, Transport.SSL);
+        }
+        catch(SSLHandshakeException e)
+        {
+            LOGGER.error("Should be able to connect using TLSv1.2", e);
+            fail("Should be able to connect using TLSv1.2");
+        }
+    }
 
 
     private void checkSSLExcluded(String clientProtocol, final Transport... transports) throws Exception
     {
         KeyStore keyStore = KeyStore.getInstance("JKS");
-        keyStore.load(new ByteArrayInputStream(Base64.getDecoder().decode(keystoreString)), "password".toCharArray());
-
+        keyStore.load(new ByteArrayInputStream(Base64.getDecoder().decode(KEYSTORE_STRING)), "password".toCharArray());
 
         final SSLContext sslContext = SSLContext.getInstance("TLS");
         KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
@@ -152,8 +230,6 @@ public class TCPandSSLTransportTest extends UnitTestBase
 
         sslContext.init(kmf.getKeyManagers(), null, null);
 
-
-
         final AmqpPort<?> port = mock(AmqpPort.class);
         when(port.getPort()).thenReturn(0);
         when(port.getName()).thenReturn("testAmqp");
@@ -163,7 +239,8 @@ public class TCPandSSLTransportTest extends UnitTestBase
         when(port.getNumberOfSelectors()).thenReturn(1);
         when(port.getSSLContext()).thenReturn(sslContext);
         when(port.getContextValue(Long.class, AmqpPort.PORT_AMQP_THREAD_POOL_KEEP_ALIVE_TIMEOUT)).thenReturn(1L);
-        when(port.getContextValue(Integer.class, AmqpPort.PORT_AMQP_ACCEPT_BACKLOG)).thenReturn(AmqpPort.DEFAULT_PORT_AMQP_ACCEPT_BACKLOG);
+        when(port.getContextValue(Integer.class, AmqpPort.PORT_AMQP_ACCEPT_BACKLOG))
+                .thenReturn(AmqpPort.DEFAULT_PORT_AMQP_ACCEPT_BACKLOG);
         when(port.getProtocolHandshakeTimeout()).thenReturn(AmqpPort.DEFAULT_PROTOCOL_HANDSHAKE_TIMEOUT);
         ObjectMapper mapper = new ObjectMapper();
         JavaType type = mapper.getTypeFactory().constructCollectionType(List.class, String.class);
@@ -192,10 +269,8 @@ public class TCPandSSLTransportTest extends UnitTestBase
         clientContext.init(null, tmf.getTrustManagers(), null);
 
         try (SSLSocket sslSocket = (SSLSocket) clientContext.getSocketFactory()
-                                                            .createSocket(InetAddress.getLoopbackAddress(),
-                                                                          transport.getAcceptingPort()))
+                .createSocket(InetAddress.getLoopbackAddress(), transport.getAcceptingPort()))
         {
-
             sslSocket.setEnabledProtocols(new String[]{clientProtocol});
             sslSocket.startHandshake();
         }
@@ -204,48 +279,4 @@ public class TCPandSSLTransportTest extends UnitTestBase
             transport.close();
         }
     }
-
-
-
-    // self signed cert keystore valid until Oct 2024
-    private static String keystoreString = "/u3+7QAAAAIAAAABAAAAAQAKc2VsZnNpZ25lZAAAAUkYmo+uAAAFATCCBP0wDgYKKwYBBAEqAhEB"
-                                           + "AQUABIIE6bR+b7FHo2BRT/WG+zDIfO8zOXoGIbuNL2znNMnvEp9xwfMQOkhKxEbVtX8uJ7HSwi1V"
-                                           + "bV2it0CA59sgvRt9awmgg+W1CLgkGKNOB+kQZbjL8R8lXmKibw4yU/EFm5rqDqPEXBRBj40TF0aT"
-                                           + "GtCCmmLPsH2pGU1wH2Ne/tozk8q7hYK6XMH/i43ZXhS9V2CKzPWrzhXmvjFKCtmYHNLj5nLLE/n0"
-                                           + "snqAssBoFSAJKmqkqHQBJNQjm4oqJFSISB8pwDX++0kvOMM7j5ryjVwihsCYuHZ6lh5BntDGF41L"
-                                           + "f4XADfv3Fma6nZQKfKs0VU2kAWUmjPpyV1FFq/ua4x6SUdZKS22YIQ3t6iO76TDABbQNyUX+Ge4n"
-                                           + "k6clF8MFswKTT0ug7zjb17d36gwl+UznvFqMSE6Zkrr9nNAcSVlQS+JaazXveiVEXTBYCAZgsNw3"
-                                           + "3KqlLWliAegnwQCQLOguw7bgusnZ/E61/TL8GTryiwN1mltbnsWkCjMj1AGUBM3sYNwbj87Vdhij"
-                                           + "iHJbjcB7q3Dak68khrCTLmqoD43KHBB5g+UMlruXYbE0elWqYpXGjI5cvt4gzfh1V+ira5DOfa4B"
-                                           + "Qskv/dh1uj2xAe1YEvF3xmdO2F6Yuzd88VO0aaPGroYPfRmh2M6rEOlwc2Ku/p23FjSWrLyzori8"
-                                           + "8/OKV4PM2b/NtY51ztTKWR/eUdX6qTPUJMK5CJiOxKGxk9PDtmsbQY685H6QVDKzTkbaPlP97+Oa"
-                                           + "xv3/2RIWR7KJzsxbqiYhX0fevRJw/RY6ZY3NEE5RAmCjzxD+1qDtu0QM/LspgPxyv5oSInAtT23U"
-                                           + "BrcNIiQ8jO+6E+fDcVhFSrs6gLGe1BwKYHsosjvup8FETLZgqKY6g1mwECA/Un2agzhI4tGC0O8v"
-                                           + "lU4VEZKrXwgy/XQ5C2vwwgLvJh94OfE20Wuf7Jjq8IUPcdF201XeYREE/vSNcBnJf22yPouJMIPk"
-                                           + "yNxlAHcapeFUi00yC19FEIpdoW/8pX2k64jx63CwwVckWWOIWlg8N+z9jsiwdjvm5wL2aFU3+wtu"
-                                           + "8Nj6Soy7Y3QYAwx17q/nUOJOk5DqLedG+/DKXVs5jghmbQ9wyzqGjGs+xYvSCXtQJygETUU/ddoM"
-                                           + "/iK4hhnZL2uqZ0wamef4ibdBbhpoRO8C7mSbi7TbDtcfysZrMb6i5MugR+NwKKzN2DznXItvpgzc"
-                                           + "Xm9j7LP8HZcQANa+1o2aIGDqK1fMSAOmBbTWlYkHPDbpoE/lx32iBNL/Aj8aKbtkwy/J2JRvo9m2"
-                                           + "uBdLK4DoDeTjqG//AwISrwm9y6xxIIPNQq7GiftN6p9KCI87U5pxqs5yUQ1g/e9DCioLe8O3Vug7"
-                                           + "+1jS1ZHWFtb4BBEF3EhkKa1AOVKNu9+M8lcG9tKWUBjnIFTD68a++6B36ShRnIZNbmbRkLC6wWdB"
-                                           + "SdyI6FWPxsPvGSF+3wq+n+0bu75N3Xsta5tEOjc67DfnQlyZtP/BIZsKxgEueOcXkjzaXMPYcrlJ"
-                                           + "2BInovQSHnSHvQfaBKqj/nKcGaDyydfdxF5fyjRPFYF+fFCWXrFkbQgAst8ymJ//UpLomfw+Ni6f"
-                                           + "xx2XQGt3941zhRuXJI2tdvUb2Czzsp0tq+h46d0WOlYQ57Q70weUQRrtARqCKoSp/gNUzQsvd+FO"
-                                           + "sUUxKRoJltRYBwAAAAEABVguNTA5AAADdTCCA3EwggJZoAMCAQICBBAXeI4wDQYJKoZIhvcNAQEL"
-                                           + "BQAwaDELMAkGA1UEBhMCVUsxETAPBgNVBAgTCFNjb3RsYW5kMRAwDgYDVQQHEwdHbGFzZ293MQ8w"
-                                           + "DQYDVQQKEwZBcGFjaGUxDTALBgNVBAsTBFFwaWQxFDASBgNVBAMTC0FwYWNoZSBRcGlkMCAXDTE0"
-                                           + "MTAxNjEwNTY1NVoYDzIxMTMwNTEwMTA1NjU1WjBoMQswCQYDVQQGEwJVSzERMA8GA1UECBMIU2Nv"
-                                           + "dGxhbmQxEDAOBgNVBAcTB0dsYXNnb3cxDzANBgNVBAoTBkFwYWNoZTENMAsGA1UECxMEUXBpZDEU"
-                                           + "MBIGA1UEAxMLQXBhY2hlIFFwaWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC520Yd"
-                                           + "1GuXh67h7HawvL5/pwTr46P45R0gx+LDGC1Equ9/wvvsVbCPL0JLDTSKl0qpgbJNMH/A740vSilb"
-                                           + "FDdqfyOuIkQZN1Ub9CkOaI5uR9RjaC2MfyNUJl7Gp64nSYk9iDX15ddZjsAijUDvET32XzfirlML"
-                                           + "dwLXv1Y5dLskV0r6xK4NdLtXi+Ndn+Uy4EllD7VMIFaLt6oG9Vo6mNl0jze7Yz/aYYtWns4x+uG8"
-                                           + "WbMgtcXo/VxCyp+4ji06XFerwfkS0zBS1wfvxd5Qb1+4dYovSn1v0AaPvZ0XwG4XErP2/svU01nc"
-                                           + "C43Z4neHdsj8Y/kmXLDD8Nc7Mpv/Wm6hAgMBAAGjITAfMB0GA1UdDgQWBBQfKBRPr/QD7PjpM3s4"
-                                           + "rD8u6ZxiijANBgkqhkiG9w0BAQsFAAOCAQEAFjyjJ8pbHf6MioZpOOlZh4lz6F+9dW1KyJR0OIc4"
-                                           + "FXnYnU/CNzjkwPminuZJoYgXBh+sVFN238YFS3I8ONEQJy8uSH33T81sklXhqnrSk9OlWk1v60wH"
-                                           + "NwwNFz5ZuGrGlvk9EFhbC8FgdkXJbz21drAl18i2oJHPdQQNwdc6mwqhpNfjqZ2opfJPbVscX1P/"
-                                           + "dbJjfcoZ01fy5687zjpN11G4egwsrya2FZiAw1WPI10OhrJgiGL5aDiDLjauNZmoM7QchUUD1cjE"
-                                           + "EwvRkU1MesliLg4y3UqDoV6ooHB4ClE2aKmIdbVB/eP1QrEEkey93ptt1z5fLk1l408AkXQtzyw7"
-                                           + "9WC+xnZta0IoYC/vO29IVsok";
 }


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


[qpid-broker-j] 03/12: QPID-8354: [Broker-J] Address review comments from Oleksandr Rudyy

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 6af60795102ff97404da21c23c9ff810396dafcc
Author: Tomas Vavricka <to...@deutsche-boerse.com>
AuthorDate: Fri Sep 20 13:51:28 2019 +0200

    QPID-8354: [Broker-J] Address review comments from Oleksandr Rudyy
    
    This closes #37
    
    (cherry picked from commit d4a3e0cab5fbf3be0760afd6999d23f088f064c4)
---
 .../server/transport/TCPandSSLTransportTest.java   | 62 ++++++++++++++++++----
 1 file changed, 53 insertions(+), 9 deletions(-)

diff --git a/broker-core/src/test/java/org/apache/qpid/server/transport/TCPandSSLTransportTest.java b/broker-core/src/test/java/org/apache/qpid/server/transport/TCPandSSLTransportTest.java
index c3ce9f3..e7726c0 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/transport/TCPandSSLTransportTest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/transport/TCPandSSLTransportTest.java
@@ -110,7 +110,7 @@ public class TCPandSSLTransportTest extends UnitTestBase
         assumeThat("The IBM JDK has different TLS defaults", getJvmVendor(), is(not(equalTo(IBM))));
         try
         {
-            checkSSLExcluded("SSLv3", Transport.SSL);
+            checkHandshakeWithTlsProtocol("SSLv3", Transport.SSL);
             fail("Should not be able to connect using SSLv3");
         }
         catch(SSLHandshakeException e)
@@ -125,7 +125,7 @@ public class TCPandSSLTransportTest extends UnitTestBase
         assumeThat("The IBM JDK has different TLS defaults", getJvmVendor(), is(not(equalTo(IBM))));
         try
         {
-            checkSSLExcluded("SSLv3", Transport.TCP, Transport.SSL);
+            checkHandshakeWithTlsProtocol("SSLv3", Transport.TCP, Transport.SSL);
             fail("Should not be able to connect using SSLv3");
         }
         catch(SSLHandshakeException e)
@@ -139,7 +139,7 @@ public class TCPandSSLTransportTest extends UnitTestBase
     {
         try
         {
-            checkSSLExcluded("TLSv1", Transport.SSL);
+            checkHandshakeWithTlsProtocol("TLSv1", Transport.SSL);
             fail("Should not be able to connect using TLSv1");
         }
         catch(SSLHandshakeException e)
@@ -153,7 +153,7 @@ public class TCPandSSLTransportTest extends UnitTestBase
     {
         try
         {
-            checkSSLExcluded("TLSv1", Transport.TCP, Transport.SSL);
+            checkHandshakeWithTlsProtocol("TLSv1", Transport.TCP, Transport.SSL);
             fail("Should not be able to connect using TLSv1");
         }
         catch(SSLHandshakeException e)
@@ -167,7 +167,7 @@ public class TCPandSSLTransportTest extends UnitTestBase
     {
         try
         {
-            checkSSLExcluded("TLSv1.1", Transport.SSL);
+            checkHandshakeWithTlsProtocol("TLSv1.1", Transport.SSL);
             fail("Should not be able to connect using TLSv1.1");
         }
         catch(SSLHandshakeException e)
@@ -181,7 +181,7 @@ public class TCPandSSLTransportTest extends UnitTestBase
     {
         try
         {
-            checkSSLExcluded("TLSv1.1", Transport.TCP, Transport.SSL);
+            checkHandshakeWithTlsProtocol("TLSv1.1", Transport.TCP, Transport.SSL);
             fail("Should not be able to connect using TLSv1.1");
         }
         catch(SSLHandshakeException e)
@@ -195,7 +195,7 @@ public class TCPandSSLTransportTest extends UnitTestBase
     {
         try
         {
-            checkSSLExcluded("TLSv1.2", Transport.SSL);
+            checkHandshakeWithTlsProtocol("TLSv1.2", Transport.SSL);
         }
         catch(SSLHandshakeException e)
         {
@@ -209,7 +209,7 @@ public class TCPandSSLTransportTest extends UnitTestBase
     {
         try
         {
-            checkSSLExcluded("TLSv1.2", Transport.TCP, Transport.SSL);
+            checkHandshakeWithTlsProtocol("TLSv1.2", Transport.TCP, Transport.SSL);
         }
         catch(SSLHandshakeException e)
         {
@@ -218,8 +218,38 @@ public class TCPandSSLTransportTest extends UnitTestBase
         }
     }
 
+    @Test
+    public void testTLSv1_3SupportOnSSLOnlyPort() throws Exception
+    {
+        assumeThat("Java 11 or above is required", isJava11OrAbove(), is(true));
+        try
+        {
+            checkHandshakeWithTlsProtocol("TLSv1.3", Transport.SSL);
+        }
+        catch(SSLHandshakeException e)
+        {
+            LOGGER.error("Should be able to connect using TLSv1.3", e);
+            fail("Should be able to connect using TLSv1.3");
+        }
+    }
+
+    @Test
+    public void testTLSv1_3SupportOnSharedPort() throws Exception
+    {
+        assumeThat("Java 11 or above is required", isJava11OrAbove(), is(true));
+        try
+        {
+            checkHandshakeWithTlsProtocol("TLSv1.3", Transport.TCP, Transport.SSL);
+        }
+        catch(SSLHandshakeException e)
+        {
+            LOGGER.error("Should be able to connect using TLSv1.3", e);
+            fail("Should be able to connect using TLSv1.3");
+        }
+    }
+
 
-    private void checkSSLExcluded(String clientProtocol, final Transport... transports) throws Exception
+    private void checkHandshakeWithTlsProtocol(String clientProtocol, final Transport... transports) throws Exception
     {
         KeyStore keyStore = KeyStore.getInstance("JKS");
         keyStore.load(new ByteArrayInputStream(Base64.getDecoder().decode(KEYSTORE_STRING)), "password".toCharArray());
@@ -279,4 +309,18 @@ public class TCPandSSLTransportTest extends UnitTestBase
             transport.close();
         }
     }
+
+    private boolean isJava11OrAbove()
+    {
+        try
+        {
+            // introduced in java 11
+            Class.forName("java.net.http.HttpClient");
+            return true;
+        }
+        catch (ClassNotFoundException e)
+        {
+            return false;
+        }
+    }
 }


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


[qpid-broker-j] 08/12: QPID-8360: [Broker-J] Change logger types to upper-case for consistency reasons

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 ae197f88b2049936071c240f1533e75b454dcee5
Author: Alex Rudyy <or...@apache.org>
AuthorDate: Mon Sep 9 15:59:14 2019 +0100

    QPID-8360: [Broker-J] Change logger types to upper-case for consistency reasons
    
    (cherry picked from commit f2876f7ce6463d8e7336ea0406dd0f0c82adbcd1)
---
 .../apache/qpid/server/logging/logback/jdbc/JDBCBrokerLoggerImpl.java   | 2 +-
 .../qpid/server/logging/logback/jdbc/JDBCVirtualHostLoggerImpl.java     | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLoggerImpl.java b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLoggerImpl.java
index 3bf49b6..6af6c09 100644
--- a/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLoggerImpl.java
+++ b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLoggerImpl.java
@@ -45,7 +45,7 @@ import org.apache.qpid.server.store.jdbc.JDBCSettings;
 public class JDBCBrokerLoggerImpl extends AbstractBrokerLogger<JDBCBrokerLoggerImpl>
         implements JDBCBrokerLogger<JDBCBrokerLoggerImpl>
 {
-    static final String CONFIGURED_OBJECT_TYPE = "Jdbc";
+    static final String CONFIGURED_OBJECT_TYPE = "JDBC";
     private final JDBCLoggerHelper _jdbcLoggerHelper;
 
     private volatile BrokerLoggerStatusListener _logbackStatusListener;
diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLoggerImpl.java b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLoggerImpl.java
index 8eb0a27..6eca1c2 100644
--- a/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLoggerImpl.java
+++ b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLoggerImpl.java
@@ -41,7 +41,7 @@ import org.apache.qpid.server.store.jdbc.JDBCSettings;
 public class JDBCVirtualHostLoggerImpl extends AbstractVirtualHostLogger<JDBCVirtualHostLoggerImpl>
         implements JDBCVirtualHostLogger<JDBCVirtualHostLoggerImpl>
 {
-    static final String CONFIGURED_OBJECT_TYPE = "Jdbc";
+    static final String CONFIGURED_OBJECT_TYPE = "JDBC";
 
     private final JDBCLoggerHelper _jdbcLoggerHelper;
 


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


[qpid-broker-j] 12/12: NO-JIRA: Exclude test dependecies from license check

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 001d9eaf21e0cc871a031c7e753123d84765c176
Author: Alex Rudyy <or...@apache.org>
AuthorDate: Sun Sep 29 23:13:50 2019 +0100

    NO-JIRA: Exclude test dependecies from license check
    
    (cherry picked from commit 4d8b5032b41e3cf2caf7366df569f3c36ea84372)
---
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index 693b218..5757c75 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1439,7 +1439,7 @@
             <!-- version specified in pluginManagement -->
             <configuration>
               <failIfWarning>true</failIfWarning>
-              <excludedScopes>provided</excludedScopes>
+              <excludedScopes>provided,test</excludedScopes>
               <outputDirectory>${license-maven-plugin-output-dir}</outputDirectory>
               <!-- Exclude logback from being checked, it is dual licensed and lists both licenses in META-INF Bundle-License   -->
               <!-- Exclude BCEL from being checked, it is ALv2 but doesnt have the necessary metadata -->


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


[qpid-broker-j] 05/12: QPID-8360: [Broker-J] Update licenseMerge for 'Eclipse Public License' to accept license specified as 'MPL 2.0 or EPL 1.0'

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 1129da1f8bc1ed55bd173de5f3d574ad17f18a6e
Author: Alex Rudyy <or...@apache.org>
AuthorDate: Mon Sep 9 11:08:20 2019 +0100

    QPID-8360: [Broker-J] Update licenseMerge for 'Eclipse Public License' to accept license specified as 'MPL 2.0 or EPL 1.0'
    
    (cherry picked from commit 55d664a768580911ce2d6efc546de7726f3b6c3e)
---
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index 7e034e7..a76c4b8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1432,7 +1432,7 @@
                 <licenseMerge>Apache Software License, Version 2.0|The Apache Software License, Version 2.0|Apache Software License - Version 2.0|Apache v2|Apache 2|Apache License, Version 2.0|Apache 2.0|Apache Public License 2.0</licenseMerge>
                 <licenseMerge>The MIT License|MIT License|MIT license</licenseMerge>
                 <licenseMerge>BSD License|New BSD|New BSD License|BSD 3-Clause|BSD Licence 3</licenseMerge>
-                <licenseMerge>Eclipse Public License - Version 1.0|Eclipse Public License - v 1.0|Eclipse Public License, Version 1.0|Eclipse Public License 1.0</licenseMerge>
+                <licenseMerge>Eclipse Public License - Version 1.0|Eclipse Public License - v 1.0|Eclipse Public License, Version 1.0|Eclipse Public License 1.0|MPL 2.0 or EPL 1.0</licenseMerge>
                 <licenseMerge>Academic Free License v2.1|AFL-2.1</licenseMerge>
                 <licenseMerge>COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0|CDDL + GPLv2 with classpath exception</licenseMerge>
               </licenseMerges>


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


[qpid-broker-j] 09/12: QPID-8363: [Broker-J] Add support for GSSAPI authentication into SimpleLDAP authentication provider

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 097031e32ad5334ddd1831d563ef0d1680f2a7bd
Author: Alex Rudyy <or...@apache.org>
AuthorDate: Sun Sep 15 00:14:19 2019 +0100

    QPID-8363: [Broker-J] Add support for GSSAPI authentication into SimpleLDAP authentication provider
    
    (cherry picked from commit 4c7aeb273736baebd49cf5c0807359ca3f15ed7e)
---
 broker-core/pom.xml                                |   5 +
 .../auth/manager/LdapAuthenticationMethod.java     |  27 +-
 .../manager/SimpleLDAPAuthenticationManager.java   |  20 +-
 .../SimpleLDAPAuthenticationManagerImpl.java       | 207 ++++++---
 .../SimpleLDAPAuthenticationManagerTest.java       | 495 +++++++++++++++++++++
 broker-core/src/test/resources/login.config        |  55 +++
 broker-core/src/test/resources/users.ldif          |  50 +++
 .../authenticationprovider/simpleldap/add.html     |  30 +-
 .../authenticationprovider/simpleldap/show.html    |   8 +
 .../authenticationprovider/simpleldap/add.js       |  36 +-
 .../authenticationprovider/simpleldap/show.js      |   7 +-
 ...oker-Security-Authentication-Providers-LDAP.xml |  10 +
 pom.xml                                            |  18 +
 13 files changed, 878 insertions(+), 90 deletions(-)

diff --git a/broker-core/pom.xml b/broker-core/pom.xml
index a7f0325..7f7bd78 100644
--- a/broker-core/pom.xml
+++ b/broker-core/pom.xml
@@ -92,6 +92,11 @@
       <scope>test</scope>
     </dependency>
 
+    <dependency>
+      <groupId>org.apache.directory.server</groupId>
+      <artifactId>apacheds-all</artifactId>
+    </dependency>
+
   </dependencies>
    
   <build>
diff --git a/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/simpleldap/show.js b/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/LdapAuthenticationMethod.java
similarity index 56%
copy from broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/simpleldap/show.js
copy to broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/LdapAuthenticationMethod.java
index 9e13956..50335e5 100644
--- a/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/simpleldap/show.js
+++ b/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/LdapAuthenticationMethod.java
@@ -17,24 +17,23 @@
  * under the License.
  */
 
-define(["qpid/common/util", "dojo/domReady!"], function (util)
+package org.apache.qpid.server.security.auth.manager;
+
+public enum LdapAuthenticationMethod
 {
+    NONE("none"),
+    SIMPLE("simple"),
+    GSSAPI("GSSAPI");
+
+    private final String _method;
 
-    function SimpleLdapAuthenticationProvider(data)
+    LdapAuthenticationMethod(String method)
     {
-        this.fields = [];
-        var attributes = data.parent.management.metadata.getMetaData("AuthenticationProvider", "SimpleLDAP").attributes;
-        for (var name in attributes)
-        {
-            this.fields.push(name);
-        }
-        util.buildUI(data.containerNode, data.parent, "authenticationprovider/simpleldap/show.html", this.fields, this);
+        _method = method;
     }
 
-    SimpleLdapAuthenticationProvider.prototype.update = function (data)
+    public String getMethod()
     {
-        util.updateUI(data, this.fields, this);
+        return _method;
     }
-
-    return SimpleLdapAuthenticationProvider;
-});
+}
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 4820675..fe650f7 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
@@ -43,10 +43,15 @@ public interface SimpleLDAPAuthenticationManager<X extends SimpleLDAPAuthenticat
     String PROVIDER_AUTH_URL = "providerAuthUrl";
     String SEARCH_CONTEXT = "searchContext";
     String LDAP_CONTEXT_FACTORY = "ldapContextFactory";
-    String SEARCH_USERNAME = "getSearchUsername";
-    String SEARCH_PASSWORD = "getSearchPassword";
+    String SEARCH_USERNAME = "searchUsername";
+    String SEARCH_PASSWORD = "searchPassword";
     String TRUST_STORE = "trustStore";
-
+    String SEARCH_FILTER = "searchFilter";
+    String GROUP_SEARCH_CONTEXT = "groupSearchContext";
+    String GROUP_SEARCH_FILTER = "groupSearchFilter";
+    String AUTHENTICATION_METHOD ="authenticationMethod";
+    String LOGIN_CONFIG_SCOPE = "loginConfigScope";
+    String LOGIN_CONFIG_SCOPE_DEFAULT = "qpid-broker-j";
 
     @ManagedAttribute( description = "LDAP server URL", mandatory = true)
     String getProviderUrl();
@@ -90,6 +95,15 @@ public interface SimpleLDAPAuthenticationManager<X extends SimpleLDAPAuthenticat
     @ManagedAttribute( description = "Defines the group search scope. If true the search for group entries is performed in the entire subtree of the group search context")
     boolean isGroupSubtreeSearchScope();
 
+    @ManagedAttribute(description = "Method of authentication to use when binding into LDAP. Supported methods: NONE, SIMPLE, GSSAPI.",
+            defaultValue = "NONE")
+    LdapAuthenticationMethod getAuthenticationMethod();
+
+    @ManagedAttribute(description = "The scope of JAAS configuration from login module to use to obtain Kerberos"
+                                    + " initiator credentials when the authentication method is GSSAPI",
+            defaultValue = LOGIN_CONFIG_SCOPE_DEFAULT)
+    String getLoginConfigScope();
+
     @DerivedAttribute
     List<String> getTlsProtocolWhiteList();
 
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 863f421..7a18c6c 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
@@ -25,6 +25,8 @@ import static java.util.Collections.unmodifiableList;
 
 import java.security.GeneralSecurityException;
 import java.security.Principal;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
@@ -47,6 +49,9 @@ import javax.naming.directory.SearchResult;
 import javax.net.SocketFactory;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLSocketFactory;
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
 
 import com.google.common.util.concurrent.ListenableFuture;
 import org.slf4j.Logger;
@@ -69,23 +74,27 @@ import org.apache.qpid.server.security.auth.sasl.SaslNegotiator;
 import org.apache.qpid.server.security.auth.sasl.SaslSettings;
 import org.apache.qpid.server.security.auth.sasl.plain.PlainNegotiator;
 import org.apache.qpid.server.security.group.GroupPrincipal;
+import org.apache.qpid.server.transport.network.security.ssl.SSLUtil;
 import org.apache.qpid.server.util.CipherSuiteAndProtocolRestrictingSSLSocketFactory;
 import org.apache.qpid.server.util.ParameterizedTypes;
+import org.apache.qpid.server.util.ServerScopedRuntimeException;
 import org.apache.qpid.server.util.StringUtil;
-import org.apache.qpid.server.transport.network.security.ssl.SSLUtil;
 
-public class SimpleLDAPAuthenticationManagerImpl extends AbstractAuthenticationManager<SimpleLDAPAuthenticationManagerImpl>
+public class SimpleLDAPAuthenticationManagerImpl
+        extends AbstractAuthenticationManager<SimpleLDAPAuthenticationManagerImpl>
         implements SimpleLDAPAuthenticationManager<SimpleLDAPAuthenticationManagerImpl>
 {
     private static final Logger LOGGER = LoggerFactory.getLogger(SimpleLDAPAuthenticationManagerImpl.class);
 
     private static final List<String> CONNECTIVITY_ATTRS = unmodifiableList(Arrays.asList(PROVIDER_URL,
-                                                                             PROVIDER_AUTH_URL,
-                                                                             SEARCH_CONTEXT,
-                                                                             LDAP_CONTEXT_FACTORY,
-                                                                             SEARCH_USERNAME,
-                                                                             SEARCH_PASSWORD,
-                                                                             TRUST_STORE));
+                                                                                          PROVIDER_AUTH_URL,
+                                                                                          SEARCH_CONTEXT,
+                                                                                          LDAP_CONTEXT_FACTORY,
+                                                                                          SEARCH_USERNAME,
+                                                                                          SEARCH_PASSWORD,
+                                                                                          TRUST_STORE,
+                                                                                          LOGIN_CONFIG_SCOPE,
+                                                                                          AUTHENTICATION_METHOD));
 
     /**
      * Environment key to instruct {@link InitialDirContext} to override the socket factory.
@@ -131,6 +140,12 @@ public class SimpleLDAPAuthenticationManagerImpl extends AbstractAuthenticationM
     @ManagedAttributeField
     private boolean _groupSubtreeSearchScope;
 
+    @ManagedAttributeField
+    private LdapAuthenticationMethod _authenticationMethod;
+
+    @ManagedAttributeField
+    private String _loginConfigScope;
+
     private List<String> _tlsProtocolWhiteList;
     private List<String>  _tlsProtocolBlackList;
 
@@ -154,9 +169,7 @@ public class SimpleLDAPAuthenticationManagerImpl extends AbstractAuthenticationM
     protected void validateOnCreate()
     {
         super.validateOnCreate();
-
-        Class<? extends SocketFactory> sslSocketFactoryOverrideClass = createSslSocketFactoryOverrideClass(_trustStore);
-        validateInitialDirContext(sslSocketFactoryOverrideClass, _providerUrl, _searchUsername, _searchPassword);
+        validateInitialDirContext(this);
     }
 
     @Override
@@ -166,11 +179,8 @@ public class SimpleLDAPAuthenticationManagerImpl extends AbstractAuthenticationM
 
         if (!disjoint(changedAttributes, CONNECTIVITY_ATTRS))
         {
-            SimpleLDAPAuthenticationManager changed = (SimpleLDAPAuthenticationManager)proxyForValidation;
-            TrustStore changedTruststore = changed.getTrustStore();
-            Class<? extends SocketFactory> sslSocketFactoryOverrideClass = createSslSocketFactoryOverrideClass(changedTruststore);
-            validateInitialDirContext(sslSocketFactoryOverrideClass, changed.getProviderUrl(), changed.getSearchUsername(),
-                                      changed.getSearchPassword());
+            SimpleLDAPAuthenticationManager changed = (SimpleLDAPAuthenticationManager) proxyForValidation;
+            validateInitialDirContext(changed);
         }
     }
 
@@ -279,6 +289,18 @@ public class SimpleLDAPAuthenticationManagerImpl extends AbstractAuthenticationM
     }
 
     @Override
+    public LdapAuthenticationMethod getAuthenticationMethod()
+    {
+        return _authenticationMethod;
+    }
+
+    @Override
+    public String getLoginConfigScope()
+    {
+        return _loginConfigScope;
+    }
+
+    @Override
     public List<String> getMechanisms()
     {
         return singletonList(PlainNegotiator.MECHANISM);
@@ -307,10 +329,24 @@ public class SimpleLDAPAuthenticationManagerImpl extends AbstractAuthenticationM
 
     private AuthenticationResult doLDAPNameAuthentication(String userId, String password)
     {
+        Subject gssapiIdentity = null;
+        if (LdapAuthenticationMethod.GSSAPI.equals(getAuthenticationMethod()))
+        {
+            try
+            {
+                gssapiIdentity = doGssApiLogin(getLoginConfigScope());
+            }
+            catch (LoginException e)
+            {
+                LOGGER.warn("JAAS Login failed", e);
+                return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR, e);
+            }
+        }
+
         final String name;
         try
         {
-            name = getNameFromId(userId);
+            name = getNameFromId(userId, gssapiIdentity);
         }
         catch (NamingException e)
         {
@@ -334,7 +370,7 @@ public class SimpleLDAPAuthenticationManagerImpl extends AbstractAuthenticationM
         InitialDirContext ctx = null;
         try
         {
-            ctx = createInitialDirContext(env, _sslSocketFactoryOverrideClass);
+            ctx = createInitialDirContext(env, _sslSocketFactoryOverrideClass, gssapiIdentity);
 
             Set<Principal> groups = Collections.emptySet();
             if (isGroupSearchRequired())
@@ -342,9 +378,9 @@ public class SimpleLDAPAuthenticationManagerImpl extends AbstractAuthenticationM
                 if (!providerAuthUrl.equals(getProviderUrl()))
                 {
                     closeSafely(ctx);
-                    ctx = createSearchInitialDirContext();
+                    ctx = createSearchInitialDirContext(gssapiIdentity);
                 }
-                groups = findGroups(ctx, name);
+                groups = findGroups(ctx, name, gssapiIdentity);
             }
 
             //Authentication succeeded
@@ -402,7 +438,8 @@ public class SimpleLDAPAuthenticationManagerImpl extends AbstractAuthenticationM
         return value != null && !"".equals(value);
     }
 
-    private Set<Principal> findGroups(DirContext context, String userDN) throws NamingException
+    private Set<Principal> findGroups(DirContext context, String userDN, final Subject gssapiIdentity)
+            throws NamingException
     {
         Set<Principal> groupPrincipals = new HashSet<>();
         if (getGroupAttributeName() != null && !"".equals(getGroupAttributeName()))
@@ -436,10 +473,11 @@ public class SimpleLDAPAuthenticationManagerImpl extends AbstractAuthenticationM
             searchControls.setSearchScope(isGroupSubtreeSearchScope()
                                                   ? SearchControls.SUBTREE_SCOPE
                                                   : SearchControls.ONELEVEL_SCOPE);
-            NamingEnumeration<?> groupEnumeration = context.search(getGroupSearchContext(),
-                                                                   getGroupSearchFilter(),
-                                                                   new String[]{encode(userDN)},
-                                                                   searchControls);
+            PrivilegedExceptionAction<NamingEnumeration<?>> search = () -> context.search(getGroupSearchContext(),
+                                                                                          getGroupSearchFilter(),
+                                                                                          new String[]{encode(userDN)},
+                                                                                          searchControls);
+            NamingEnumeration<?> groupEnumeration = invokeContextOperationAs(gssapiIdentity, search);
             while (groupEnumeration.hasMore())
             {
                 SearchResult result = (SearchResult) groupEnumeration.next();
@@ -491,8 +529,9 @@ public class SimpleLDAPAuthenticationManagerImpl extends AbstractAuthenticationM
         return env;
     }
 
-    private InitialDirContext createInitialDirContext(Hashtable<String, Object> env,
-                                                      Class<? extends SocketFactory> sslSocketFactoryOverrideClass) throws NamingException
+    private InitialDirContext createInitialDirContext(final Hashtable<String, Object> env,
+                                                      final Class<? extends SocketFactory> sslSocketFactoryOverrideClass,
+                                                      final Subject gssapiIdentity) throws NamingException
     {
         ClassLoader existingContextClassLoader = null;
 
@@ -508,7 +547,7 @@ public class SimpleLDAPAuthenticationManagerImpl extends AbstractAuthenticationM
                 Thread.currentThread().setContextClassLoader(sslSocketFactoryOverrideClass.getClassLoader());
                 revertContentClassLoader = true;
             }
-            return new InitialDirContext(env);
+            return invokeContextOperationAs(gssapiIdentity, () -> new InitialDirContext(env));
         }
         finally
         {
@@ -564,27 +603,45 @@ public class SimpleLDAPAuthenticationManagerImpl extends AbstractAuthenticationM
                ", providerUrl=" + _providerUrl + ", providerAuthUrl=" + _providerAuthUrl +
                ", searchContext=" + _searchContext + ", state=" + getState() +
                ", searchFilter=" + _searchFilter + ", ldapContextFactory=" + _ldapContextFactory +
-               ", bindWithoutSearch=" + _bindWithoutSearch  + ", trustStore=" + _trustStore  +
-               ", searchUsername=" + _searchUsername + "]";
+               ", bindWithoutSearch=" + _bindWithoutSearch + ", trustStore=" + _trustStore +
+               ", searchUsername=" + _searchUsername + ", loginConfigScope=" + _loginConfigScope +
+               ", authenticationMethod=" + _authenticationMethod + "]";
     }
 
-    private void validateInitialDirContext(Class<? extends SocketFactory> sslSocketFactoryOverrideClass,
-                                           final String providerUrl,
-                                           final String searchUsername, final String searchPassword)
+    private void validateInitialDirContext(final SimpleLDAPAuthenticationManager<?> authenticationProvider)
     {
-        Hashtable<String,Object> env = createInitialDirContextEnvironment(providerUrl);
+        final TrustStore truststore = authenticationProvider.getTrustStore();
+        final Class<? extends SocketFactory> sslSocketFactoryOverrideClass =
+                createSslSocketFactoryOverrideClass(truststore);
 
-        setupSearchContext(env, searchUsername, searchPassword);
+        final Hashtable<String, Object> env =
+                createInitialDirContextEnvironment(authenticationProvider.getProviderUrl());
+        setAuthenticationProperties(env,
+                                    authenticationProvider.getSearchUsername(),
+                                    authenticationProvider.getSearchPassword(),
+                                    authenticationProvider.getAuthenticationMethod());
 
         InitialDirContext ctx = null;
         try
         {
-            ctx = createInitialDirContext(env, sslSocketFactoryOverrideClass);
+            Subject gssapiIdentity = null;
+            if (LdapAuthenticationMethod.GSSAPI.equals(authenticationProvider.getAuthenticationMethod()))
+            {
+                gssapiIdentity = doGssApiLogin(authenticationProvider.getLoginConfigScope());
+            }
+            ctx = createInitialDirContext(env, sslSocketFactoryOverrideClass, gssapiIdentity);
         }
         catch (NamingException e)
         {
-            LOGGER.error("Failed to establish connectivity to the ldap server for '{}'", providerUrl, e);
-            throw new IllegalConfigurationException("Failed to establish connectivity to the ldap server." , e);
+            LOGGER.debug("Failed to establish connectivity to the ldap server for '{}'",
+                         authenticationProvider.getProviderUrl(),
+                         e);
+            throw new IllegalConfigurationException("Failed to establish connectivity to the ldap server.", e);
+        }
+        catch (LoginException e)
+        {
+            LOGGER.debug("JAAS login failed ", e);
+            throw new IllegalConfigurationException("JAAS login failed.", e);
         }
         finally
         {
@@ -592,14 +649,26 @@ public class SimpleLDAPAuthenticationManagerImpl extends AbstractAuthenticationM
         }
     }
 
-    private void setupSearchContext(final Hashtable<String, Object> env,
-                                    final String searchUsername, final String searchPassword)
+    private void setAuthenticationProperties(final Hashtable<String, Object> env,
+                                             final String userName,
+                                             final String password,
+                                             final LdapAuthenticationMethod authenticationMethod)
     {
-        if(_searchUsername != null && _searchUsername.trim().length()>0)
+        if (LdapAuthenticationMethod.GSSAPI.equals(authenticationMethod))
+        {
+            env.put(Context.SECURITY_AUTHENTICATION, "GSSAPI");
+        }
+        else if (LdapAuthenticationMethod.SIMPLE.equals(authenticationMethod))
         {
             env.put(Context.SECURITY_AUTHENTICATION, "simple");
-            env.put(Context.SECURITY_PRINCIPAL, searchUsername);
-            env.put(Context.SECURITY_CREDENTIALS, searchPassword);
+            if (userName != null)
+            {
+                env.put(Context.SECURITY_PRINCIPAL, userName);
+            }
+            if (password != null)
+            {
+                env.put(Context.SECURITY_CREDENTIALS, password);
+            }
         }
         else
         {
@@ -607,11 +676,12 @@ public class SimpleLDAPAuthenticationManagerImpl extends AbstractAuthenticationM
         }
     }
 
-    private String getNameFromId(String id) throws NamingException
+    private String getNameFromId(final String id, final Subject gssapiIdentity)
+            throws NamingException
     {
-        if(!isBindWithoutSearch())
+        if (!isBindWithoutSearch())
         {
-            InitialDirContext ctx = createSearchInitialDirContext();
+            InitialDirContext ctx = createSearchInitialDirContext(gssapiIdentity);
 
             try
             {
@@ -622,7 +692,13 @@ public class SimpleLDAPAuthenticationManagerImpl extends AbstractAuthenticationM
                 NamingEnumeration<?> namingEnum = null;
 
                 LOGGER.debug("Searching for '{}'", id);
-                namingEnum = ctx.search(_searchContext, _searchFilter, new String[]{id}, searchControls);
+                namingEnum = invokeContextOperationAs(gssapiIdentity,
+                                                      (PrivilegedExceptionAction<NamingEnumeration<?>>) () -> ctx.search(
+                                                              _searchContext,
+                                                              _searchFilter,
+                                                              new String[]{id},
+                                                              searchControls));
+
                 if (namingEnum.hasMore())
                 {
                     SearchResult result = (SearchResult) namingEnum.next();
@@ -645,14 +721,45 @@ public class SimpleLDAPAuthenticationManagerImpl extends AbstractAuthenticationM
         {
             return id;
         }
+    }
 
+    private <T> T invokeContextOperationAs(final Subject identity, final PrivilegedExceptionAction<T> action)
+            throws NamingException
+    {
+        try
+        {
+            return Subject.doAs(identity, action);
+        }
+        catch (PrivilegedActionException e)
+        {
+            final Exception exception = e.getException();
+            if (exception instanceof NamingException)
+            {
+                throw (NamingException) exception;
+            }
+            else if (exception instanceof RuntimeException)
+            {
+                throw (RuntimeException) exception;
+            }
+            else
+            {
+                throw new ServerScopedRuntimeException(exception);
+            }
+        }
+    }
+
+    private Subject doGssApiLogin(final String configScope) throws LoginException
+    {
+        LoginContext loginContext = new LoginContext(configScope);
+        loginContext.login();
+        return loginContext.getSubject();
     }
 
-    private InitialDirContext createSearchInitialDirContext() throws NamingException
+    private InitialDirContext createSearchInitialDirContext(final Subject gssapiIdentity) throws NamingException
     {
         Hashtable<String, Object> env = createInitialDirContextEnvironment(_providerUrl);
-        setupSearchContext(env, _searchUsername, _searchPassword);
-        return createInitialDirContext(env, _sslSocketFactoryOverrideClass);
+        setAuthenticationProperties(env, _searchUsername, _searchPassword, _authenticationMethod);
+        return createInitialDirContext(env, _sslSocketFactoryOverrideClass, gssapiIdentity);
     }
 
 
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
new file mode 100644
index 0000000..b5dd2a1
--- /dev/null
+++ b/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerTest.java
@@ -0,0 +1,495 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.server.security.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.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.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.URL;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+import java.security.Principal;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.security.auth.Subject;
+import javax.security.auth.kerberos.KerberosPrincipal;
+
+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;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.util.Strings;
+import org.apache.directory.server.annotations.CreateKdcServer;
+import org.apache.directory.server.annotations.CreateLdapServer;
+import org.apache.directory.server.annotations.CreateTransport;
+import org.apache.directory.server.annotations.SaslMechanism;
+import org.apache.directory.server.core.annotations.ApplyLdifFiles;
+import org.apache.directory.server.core.annotations.CreateDS;
+import org.apache.directory.server.core.annotations.CreatePartition;
+import org.apache.directory.server.core.api.DirectoryService;
+import org.apache.directory.server.core.integ.CreateLdapServerRule;
+import org.apache.directory.server.core.kerberos.KeyDerivationInterceptor;
+import org.apache.directory.server.factory.ServerAnnotationProcessor;
+import org.apache.directory.server.kerberos.kdc.KdcServer;
+import org.apache.directory.server.kerberos.shared.crypto.encryption.KerberosKeyFactory;
+import org.apache.directory.server.kerberos.shared.keytab.Keytab;
+import org.apache.directory.server.kerberos.shared.keytab.KeytabEntry;
+import org.apache.directory.server.ldap.LdapServer;
+import org.apache.directory.server.ldap.handlers.sasl.gssapi.GssapiMechanismHandler;
+import org.apache.directory.server.ldap.handlers.sasl.plain.PlainMechanismHandler;
+import org.apache.directory.shared.kerberos.KerberosTime;
+import org.apache.directory.shared.kerberos.codec.types.EncryptionType;
+import org.apache.directory.shared.kerberos.components.EncryptionKey;
+import org.junit.After;
+import org.junit.Before;
+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.Broker;
+import org.apache.qpid.server.model.BrokerTestHelper;
+import org.apache.qpid.server.security.auth.AuthenticationResult;
+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.test.utils.SystemPropertySetter;
+import org.apache.qpid.test.utils.TestFileUtils;
+import org.apache.qpid.test.utils.UnitTestBase;
+
+@CreateDS(
+        name = "testDS",
+        partitions =
+                {
+                        @CreatePartition(name = "test", suffix = "dc=qpid,dc=org")
+                },
+        additionalInterceptors =
+                {
+                        KeyDerivationInterceptor.class
+                }
+)
+@CreateLdapServer(
+        transports =
+                {
+                        @CreateTransport(protocol = "LDAP")
+                },
+        allowAnonymousAccess = true,
+        saslHost = "localhost",
+        saslPrincipal = "ldap/localhost@QPID.ORG",
+        saslMechanisms =
+                {
+                        @SaslMechanism(name = SupportedSaslMechanisms.PLAIN, implClass = PlainMechanismHandler.class),
+                        @SaslMechanism(name = SupportedSaslMechanisms.GSSAPI, implClass = GssapiMechanismHandler.class)
+                }
+)
+@CreateKdcServer(
+        transports =
+                {
+                        @CreateTransport(protocol = "TCP", port = 0)
+                },
+        searchBaseDn = "ou=users,dc=qpid,dc=org")
+@ApplyLdifFiles("users.ldif")
+public class SimpleLDAPAuthenticationManagerTest extends UnitTestBase
+{
+    private static final Logger LOGGER = LoggerFactory.getLogger(SimpleLDAPAuthenticationManagerTest.class);
+    private static final String ROOT = "dc=qpid,dc=org";
+    private static final String USERS_DN = "ou=users," + ROOT;
+    private static final String SEARCH_CONTEXT_VALUE = USERS_DN;
+    private static final String SEARCH_FILTER_VALUE = "(uid={0})";
+    private static final String LDAP_URL_TEMPLATE = "ldap://localhost:%d";
+    private static final String USER_1_NAME = "test1";
+    private static final String USER_1_PASSWORD = "password1";
+    private static final String USER_1_DN = "cn=integration-test1,ou=users,dc=qpid,dc=org";
+    private static final String GROUP_SEARCH_CONTEXT_VALUE = "ou=groups,dc=qpid,dc=org";
+    private static final String GROUP_SEARCH_FILTER_VALUE = "(member={0})";
+    private static final String LDAP_SERVICE_NAME = "ldap";
+    private static final String REALM = "QPID.ORG";
+    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();
+
+    @ClassRule
+    public static CreateLdapServerRule LDAP = new CreateLdapServerRule();
+
+    @ClassRule
+    public static final SystemPropertySetter SYSTEM_PROPERTY_SETTER = new SystemPropertySetter();
+
+    private SimpleLDAPAuthenticationManager _authenticationProvider;
+
+    @Before
+    public void setUp()
+    {
+        _authenticationProvider = createAuthenticationProvider();
+    }
+
+    @After
+    public void tearDown()
+    {
+        if (_authenticationProvider != null)
+        {
+            _authenticationProvider.close();
+        }
+    }
+
+    @Test
+    public void testAuthenticateSuccess()
+    {
+        final AuthenticationResult result = _authenticationProvider.authenticate(USER_1_NAME, USER_1_PASSWORD);
+        assertEquals(AuthenticationResult.AuthenticationStatus.SUCCESS, result.getStatus());
+        assertEquals(USER_1_DN, result.getMainPrincipal().getName());
+    }
+
+    @Test
+    public void testAuthenticateFailure()
+    {
+        final AuthenticationResult result = _authenticationProvider.authenticate(USER_1_NAME, USER_1_PASSWORD + "_");
+        assertEquals(AuthenticationResult.AuthenticationStatus.ERROR, result.getStatus());
+    }
+
+    @Test
+    public void testSaslPlainNegotiatorPlain()
+    {
+        final SaslSettings saslSettings = mock(SaslSettings.class);
+        when(saslSettings.getLocalFQDN()).thenReturn(HOSTNAME);
+
+        final SaslNegotiator negotiator = _authenticationProvider.createSaslNegotiator("PLAIN", saslSettings, null);
+        assertNotNull("Could not create SASL negotiator for mechanism 'PLAIN'", negotiator);
+
+        final AuthenticationResult result = negotiator.handleResponse(new byte[0]);
+        assertEquals("Unexpected authentication status",
+                     AuthenticationResult.AuthenticationStatus.CONTINUE,
+                     result.getStatus());
+
+        final AuthenticationResult result2 =
+                negotiator.handleResponse(String.format("\0%s\0%s", USER_1_NAME, USER_1_PASSWORD).getBytes(UTF_8));
+
+        assertEquals("Unexpected authentication status",
+                     AuthenticationResult.AuthenticationStatus.SUCCESS,
+                     result2.getStatus());
+    }
+
+    @Test
+    public void testGroups()
+    {
+        _authenticationProvider.close();
+        final Map<String, Object> groupSetUp = new HashMap<>();
+        groupSetUp.put(SimpleLDAPAuthenticationManager.GROUP_SEARCH_CONTEXT, GROUP_SEARCH_CONTEXT_VALUE);
+        groupSetUp.put(SimpleLDAPAuthenticationManager.GROUP_SEARCH_FILTER, GROUP_SEARCH_FILTER_VALUE);
+        _authenticationProvider = createAuthenticationProvider(groupSetUp);
+
+        final AuthenticationResult result = _authenticationProvider.authenticate(USER_1_NAME, USER_1_PASSWORD);
+        assertEquals(AuthenticationResult.AuthenticationStatus.SUCCESS, result.getStatus());
+        assertEquals(USER_1_DN, result.getMainPrincipal().getName());
+
+        final Set<Principal> principals = result.getPrincipals();
+        assertNotNull(principals);
+
+        final Principal groupPrincipal = principals.stream()
+                                                   .filter(p -> "cn=group1,ou=groups,dc=qpid,dc=org".equalsIgnoreCase(p.getName()))
+                                                   .findFirst()
+                                                   .orElse(null);
+        assertNotNull(groupPrincipal);
+    }
+
+    @Test
+    public void testAuthenticateSuccessWhenCachingEnabled()
+    {
+        _authenticationProvider.close();
+        _authenticationProvider = createCachingAuthenticationProvider();
+
+        final SocketConnectionPrincipal principal = mock(SocketConnectionPrincipal.class);
+        when(principal.getRemoteAddress()).thenReturn(new InetSocketAddress(HOSTNAME, 5672));
+        final Subject subject =
+                new Subject(true, Collections.singleton(principal), Collections.emptySet(), Collections.emptySet());
+        final AuthenticationResult result = Subject.doAs(subject,
+                                                         (PrivilegedAction<AuthenticationResult>) () -> _authenticationProvider
+                                                                 .authenticate(USER_1_NAME, USER_1_PASSWORD));
+        assertEquals(AuthenticationResult.AuthenticationStatus.SUCCESS, result.getStatus());
+        assertEquals(USER_1_DN, result.getMainPrincipal().getName());
+    }
+
+    @Test
+    public void testGssapiBindWithKeyTab() throws Exception
+    {
+        setUpKerberosAndJaas();
+
+        final Map<String, Object> attributes = new HashMap<>();
+        attributes.put(SimpleLDAPAuthenticationManager.AUTHENTICATION_METHOD, LdapAuthenticationMethod.GSSAPI.name());
+        attributes.put(SimpleLDAPAuthenticationManager.LOGIN_CONFIG_SCOPE, LOGIN_SCOPE);
+        final SimpleLDAPAuthenticationManagerImpl authenticationProvider = createAuthenticationProvider(attributes);
+        final AuthenticationResult result = authenticationProvider.authenticate(USER_1_NAME, USER_1_PASSWORD);
+        assertEquals(AuthenticationResult.AuthenticationStatus.SUCCESS, result.getStatus());
+        assertEquals(USER_1_DN, result.getMainPrincipal().getName());
+    }
+
+    @Test
+    public void testChangeAuthenticationToGssapi() throws Exception
+    {
+        setUpKerberosAndJaas();
+
+        final Map<String, Object> attributes = new HashMap<>();
+        attributes.put(SimpleLDAPAuthenticationManager.AUTHENTICATION_METHOD, LdapAuthenticationMethod.GSSAPI.name());
+        attributes.put(SimpleLDAPAuthenticationManager.LOGIN_CONFIG_SCOPE, LOGIN_SCOPE);
+        _authenticationProvider.setAttributes(attributes);
+
+        final AuthenticationResult result = _authenticationProvider.authenticate(USER_1_NAME, USER_1_PASSWORD);
+        assertEquals(AuthenticationResult.AuthenticationStatus.SUCCESS, result.getStatus());
+        assertEquals(USER_1_DN, result.getMainPrincipal().getName());
+    }
+
+    @Test
+    public void testChangeAuthenticationToGssapiWithInvalidScope() throws Exception
+    {
+        setUpKerberosAndJaas();
+
+        final Map<String, Object> attributes = new HashMap<>();
+        attributes.put(SimpleLDAPAuthenticationManager.AUTHENTICATION_METHOD, LdapAuthenticationMethod.GSSAPI.name());
+        attributes.put(SimpleLDAPAuthenticationManager.LOGIN_CONFIG_SCOPE, "non-existing");
+        try
+        {
+            _authenticationProvider.setAttributes(attributes);
+            fail("Exception is expected");
+        }
+        catch (IllegalConfigurationException e)
+        {
+            // pass
+        }
+    }
+
+    @Test
+    public void testChangeAuthenticationToGssapiWhenConfigIsBroken() throws Exception
+    {
+        setUpKerberosAndJaas();
+
+        final Map<String, Object> attributes = new HashMap<>();
+        attributes.put(SimpleLDAPAuthenticationManager.AUTHENTICATION_METHOD, LdapAuthenticationMethod.GSSAPI.name());
+        attributes.put(SimpleLDAPAuthenticationManager.LOGIN_CONFIG_SCOPE, "ldap-gssapi-bind-broken");
+        try
+        {
+            _authenticationProvider.setAttributes(attributes);
+            fail("Exception is expected");
+        }
+        catch (IllegalConfigurationException e)
+        {
+            // pass
+        }
+    }
+
+    @Test
+    public void testChangeAuthenticationToGssapiNoScopeProvided() throws Exception
+    {
+        setUpKerberosAndJaas();
+
+        final Map<String, Object> attributes = new HashMap<>();
+        attributes.put(SimpleLDAPAuthenticationManager.AUTHENTICATION_METHOD, LdapAuthenticationMethod.GSSAPI.name());
+        _authenticationProvider.setAttributes(attributes);
+
+        final AuthenticationResult result = _authenticationProvider.authenticate(USER_1_NAME, USER_1_PASSWORD);
+        assertEquals(AuthenticationResult.AuthenticationStatus.SUCCESS, result.getStatus());
+        assertEquals(USER_1_DN, result.getMainPrincipal().getName());
+    }
+
+    private SimpleLDAPAuthenticationManagerImpl createAuthenticationProvider()
+    {
+        return createAuthenticationProvider(Collections.emptyMap());
+    }
+
+    private SimpleLDAPAuthenticationManagerImpl createCachingAuthenticationProvider()
+    {
+        final Map<String, String> context = Collections.singletonMap(AUTHENTICATION_CACHE_MAX_SIZE, "1");
+        final Map<String, Object> attributes =
+                Collections.singletonMap(SimpleLDAPAuthenticationManager.CONTEXT, context);
+        return createAuthenticationProvider(attributes);
+    }
+
+    private SimpleLDAPAuthenticationManagerImpl createAuthenticationProvider(final Map<String, Object> settings)
+    {
+        final Broker<?> broker = BrokerTestHelper.createBrokerMock();
+        final Map<String, Object> attributes = new HashMap<>();
+        attributes.put(SimpleLDAPAuthenticationManager.NAME, getTestName());
+        attributes.put(SimpleLDAPAuthenticationManager.SEARCH_CONTEXT, SEARCH_CONTEXT_VALUE);
+        attributes.put(SimpleLDAPAuthenticationManager.PROVIDER_URL,
+                       String.format(LDAP_URL_TEMPLATE, LDAP.getLdapServer().getPort()));
+        attributes.put(SimpleLDAPAuthenticationManager.SEARCH_FILTER, SEARCH_FILTER_VALUE);
+        attributes.put(SimpleLDAPAuthenticationManager.CONTEXT,
+                       Collections.singletonMap(AUTHENTICATION_CACHE_MAX_SIZE, "0"));
+        attributes.putAll(settings);
+        final SimpleLDAPAuthenticationManagerImpl authenticationProvider =
+                new SimpleLDAPAuthenticationManagerImpl(attributes, broker);
+        authenticationProvider.open();
+        return authenticationProvider;
+    }
+
+
+    private void setUpKerberosAndJaas() throws Exception
+    {
+        assumeThat(getJvmVendor(), not(JvmVendor.IBM));
+        if (KERBEROS_SETUP.compareAndSet(false, true))
+        {
+            setUpKerberos();
+            setUpJaas();
+        }
+    }
+
+    private void setUpKerberos() throws Exception
+    {
+        final LdapServer ldapServer = LDAP.getLdapServer();
+        final KdcServer kdcServer =
+                ServerAnnotationProcessor.getKdcServer(LDAP.getDirectoryService(), ldapServer.getPort() + 1);
+        kdcServer.getConfig().setPaEncTimestampRequired(false);
+        final KerberosPrincipal servicePrincipal =
+                new KerberosPrincipal(LDAP_SERVICE_NAME + "/" + HOSTNAME + "@" + REALM,
+                                      KerberosPrincipal.KRB_NT_SRV_HST);
+        final String servicePrincipalName = servicePrincipal.getName();
+        ldapServer.setSaslHost(servicePrincipalName.substring(servicePrincipalName.indexOf("/") + 1,
+                                                              servicePrincipalName.indexOf("@")));
+        ldapServer.setSaslPrincipal(servicePrincipalName);
+        ldapServer.setSearchBaseDn(USERS_DN);
+
+        final String krb5confPath = createKrb5Conf(kdcServer.getTransports()[0].getPort());
+        SYSTEM_PROPERTY_SETTER.setSystemProperty("java.security.krb5.conf", krb5confPath);
+
+        createPrincipal("KDC", "KDC", "krbtgt", UUID.randomUUID().toString(), "krbtgt/" + REALM + "@" + REALM);
+        createPrincipal("Service", "LDAP Service", "ldap", UUID.randomUUID().toString(), servicePrincipalName);
+    }
+
+    private void setUpJaas() throws LdapException, IOException
+    {
+        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", resource.getPath());
+        SYSTEM_PROPERTY_SETTER.setSystemProperty("sun.security.krb5.debug", "true");
+    }
+
+    private String createKrb5Conf(final int port) throws IOException
+    {
+        final File file = createFile("krb5", ".conf");
+        final String config = String.format("[libdefaults]%1$s"
+                                            + "    default_realm = %2$s%1$s"
+                                            + "    udp_preference_limit = 1%1$s"
+                                            + "[realms]%1$s"
+                                            + "    %2$s = {%1$s"
+                                            + "    kdc = %3$s%1$s"
+                                            + "    }%1$s"
+                                            + "[domain_realm]%1$s"
+                                            + "    .%4$s = %2$s%1$s"
+                                            + "    %4$s = %2$s%1$s",
+                                            LINE_SEPARATOR,
+                                            REALM,
+                                            HOSTNAME + ":" + port,
+                                            Strings.toLowerCaseAscii(REALM));
+        LOGGER.debug("krb5.conf:" + config);
+        TestFileUtils.saveTextContentInFile(config, file);
+        return file.getAbsolutePath();
+    }
+
+    private void createPrincipal(final String sn,
+                                 final String cn,
+                                 final String uid,
+                                 final String userPassword,
+                                 final String kerberosPrincipalName) throws LdapException
+    {
+        final DirectoryService directoryService = LDAP.getDirectoryService();
+        final Entry entry = new DefaultEntry(directoryService.getSchemaManager());
+        entry.setDn(String.format("uid=%s,%s", uid, USERS_DN));
+        entry.add("objectClass", "top", "person", "inetOrgPerson", "krb5principal", "krb5kdcentry");
+        entry.add("cn", cn);
+        entry.add("sn", sn);
+        entry.add("uid", uid);
+        entry.add("userPassword", userPassword);
+        entry.add("krb5PrincipalName", kerberosPrincipalName);
+        entry.add("krb5KeyVersionNumber", "0");
+        directoryService.getAdminSession().add(entry);
+    }
+
+    private void createPrincipal(String uid, String userPassword) throws LdapException
+    {
+        createPrincipal(uid, uid, uid, userPassword, uid + "@" + REALM);
+    }
+
+    private void createPrincipal(final File keyTabFile, final String... principals) throws LdapException, IOException
+    {
+        final Keytab keytab = new Keytab();
+        final List<KeytabEntry> entries = new ArrayList<>();
+        final String password = UUID.randomUUID().toString();
+        for (final String principal : principals)
+        {
+            createPrincipal(principal, password);
+            final String principalName = principal + "@" + REALM;
+            final KerberosTime timestamp = new KerberosTime();
+            final Map<EncryptionType, EncryptionKey> keys = KerberosKeyFactory.getKerberosKeys(principalName, password);
+            keys.forEach((type, key) -> entries.add(new KeytabEntry(principalName,
+                                                                    1,
+                                                                    timestamp,
+                                                                    (byte) key.getKeyVersion(),
+                                                                    key)));
+        }
+        keytab.setEntries(entries);
+        keytab.write(keyTabFile);
+    }
+
+    private void createKeyTab(String... principals) throws LdapException, IOException
+    {
+        final File keyTabFile = createFile("kerberos", ".keytab");
+        createPrincipal(keyTabFile, principals);
+    }
+
+    private File createFile(final String prefix, final String suffix) throws IOException
+    {
+        final Path targetDir = FileSystems.getDefault().getPath("target");
+        final File file = new File(targetDir.toFile(), prefix + suffix);
+        if (file.exists())
+        {
+            if (!file.delete())
+            {
+                throw new IOException(String.format("Cannot delete existing file '%s'", file.getAbsolutePath()));
+            }
+        }
+        if (!file.createNewFile())
+        {
+            throw new IOException(String.format("Cannot create file '%s'", file.getAbsolutePath()));
+        }
+        return file;
+    }
+}
diff --git a/broker-core/src/test/resources/login.config b/broker-core/src/test/resources/login.config
new file mode 100644
index 0000000..d458516
--- /dev/null
+++ b/broker-core/src/test/resources/login.config
@@ -0,0 +1,55 @@
+/*
+ * 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.sun.security.auth.module.Krb5LoginModule required
+    useKeyTab=true
+    debug=true
+    storeKey=true
+    doNotPrompt=true
+    isInitiator=true
+    refreshKrb5Config=true
+    realm="QPID.ORG"
+    principal="service/localhost"
+    keyTab="target/kerberos.keytab";
+};
+
+ldap-gssapi-bind-broken {
+    com.sun.security.auth.module.Krb5LoginModule required
+    useKeyTab=true
+    debug=true
+    storeKey=true
+    doNotPrompt=true
+    isInitiator=true
+    refreshKrb5Config=true
+    realm="QPID.ORG"
+    principal="service/localhost"
+    keyTab="target/kerberos-non-existing.keytab";
+};
+
+qpid-broker-j {
+    com.sun.security.auth.module.Krb5LoginModule required
+    useKeyTab=true
+    debug=true
+    storeKey=true
+    doNotPrompt=true
+    isInitiator=true
+    refreshKrb5Config=true
+    realm="QPID.ORG"
+    principal="service/localhost"
+    keyTab="target/kerberos.keytab";
+};
diff --git a/broker-core/src/test/resources/users.ldif b/broker-core/src/test/resources/users.ldif
new file mode 100644
index 0000000..0d76baa
--- /dev/null
+++ b/broker-core/src/test/resources/users.ldif
@@ -0,0 +1,50 @@
+#
+# 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.
+#
+
+version: 1
+dn: dc=qpid,dc=org
+objectClass: domain
+objectClass: top
+dc: tests
+
+dn: ou=users,dc=qpid,dc=org
+objectClass: organizationalUnit
+objectClass: top
+ou: Users
+
+dn: ou=groups,dc=qpid,dc=org
+objectClass: organizationalUnit
+objectClass: top
+ou: Groups
+
+dn: cn=integration-test1,ou=users,dc=qpid,dc=org
+objectClass: inetOrgPerson
+objectClass: organizationalPerson
+objectClass: person
+objectClass: top
+cn: integration-test1
+sn: ldap-integration-test1
+uid: test1
+userPassword: password1
+
+dn: cn=group1,ou=groups,dc=qpid,dc=org
+cn: Group1
+member: cn=integration-test1,ou=Users,dc=qpid,dc=org
+objectClass: groupOfNames
+objectClass: top
diff --git a/broker-plugins/management-http/src/main/java/resources/authenticationprovider/simpleldap/add.html b/broker-plugins/management-http/src/main/java/resources/authenticationprovider/simpleldap/add.html
index 5b88a3c..3601540 100644
--- a/broker-plugins/management-http/src/main/java/resources/authenticationprovider/simpleldap/add.html
+++ b/broker-plugins/management-http/src/main/java/resources/authenticationprovider/simpleldap/add.html
@@ -68,11 +68,38 @@
                               promptMessage: 'Fully qualified class name for LDAP Context Factory'"/>
         </div>
     </div>
-
+    <div class="clear">
+        <div class="formLabel-labelCell tableContainer-labelCell">Authentication Method:</div>
+        <div class="tableContainer-valueCell formLabel-controlCell">
+            <select class="authenticationMethod" data-dojo-type="dijit/form/FilteringSelect"
+                    id="ldapAuthenticationMethod"
+                    data-dojo-props="
+                                    required: false,
+                                    name: 'authenticationMethod',
+                                    placeHolder: 'Select authentication method',
+                                    promptMessage: 'Select authentication method to bind into LDAP server',
+                                    title: 'Select authentication method to bind into LDAP server',
+                                    searchAttr: 'name'">
+            </select>
+        </div>
+    </div>
+    <div class="clear">
+        <div class="formLabel-labelCell tableContainer-labelCell">Login Config Scope:</div>
+        <div class="formLabel-controlCell tableContainer-valueCell">
+            <input type="text" class="loginConfigScope"
+                   data-dojo-type="dijit/form/ValidationTextBox"
+                   data-dojo-props="
+                              name: 'loginConfigScope',
+                              placeHolder: 'loginConfigScope',
+                              title: 'Login configuration name for GSSAPI authentication',
+                              promptMessage: 'Login configuration name for GSSAPI authentication'"/>
+        </div>
+    </div>
     <div class="clear">
         <div class="formLabel-labelCell tableContainer-labelCell">Search username:</div>
         <div class="formLabel-controlCell tableContainer-valueCell">
             <input type="text" class="searchUsername"
+                   id="ldapSearchUsername"
                    data-dojo-type="dijit/form/ValidationTextBox"
                    data-dojo-props="
                               name: 'searchUsername',
@@ -85,6 +112,7 @@
         <div class="formLabel-labelCell tableContainer-labelCell">Search password:</div>
         <div class="formLabel-controlCell tableContainer-valueCell">
             <input type="password" class="searchPassword"
+                   id="ldapSearchPassword"
                    data-dojo-type="dijit/form/ValidationTextBox"
                    data-dojo-props="
                               name: 'searchPassword',
diff --git a/broker-plugins/management-http/src/main/java/resources/authenticationprovider/simpleldap/show.html b/broker-plugins/management-http/src/main/java/resources/authenticationprovider/simpleldap/show.html
index d71e01f..94bf306 100644
--- a/broker-plugins/management-http/src/main/java/resources/authenticationprovider/simpleldap/show.html
+++ b/broker-plugins/management-http/src/main/java/resources/authenticationprovider/simpleldap/show.html
@@ -41,6 +41,14 @@
         <div class="formLabel-labelCell">Search password:</div>
         <div><span class="searchPassword" ></span></div>
     </div>
+    <div class="clear">
+        <div class="formLabel-labelCell">Authentication method:</div>
+        <div><span class="authenticationMethod" ></span></div>
+    </div>
+    <div class="clear">
+        <div class="formLabel-labelCell">Login config scope:</div>
+        <div><span class="loginConfigScope" ></span></div>
+    </div>
     <div class="clear"></div>
 
     <div class="formBox">
diff --git a/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/simpleldap/add.js b/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/simpleldap/add.js
index 06bd2d5..edc8243 100644
--- a/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/simpleldap/add.js
+++ b/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/simpleldap/add.js
@@ -81,6 +81,7 @@ define(["dojo/query",
                 .then(function (trustStores)
                 {
                     that._initTrustStores(trustStores, data.containerNode);
+                    that._initAuthenticationMethods(data.parent.management.metadata, data.containerNode);
                     if (data.data)
                     {
                         that._initFields(data.data, data.containerNode, data.parent.management.metadata);
@@ -137,28 +138,23 @@ define(["dojo/query",
             var trustStore = registry.byNode(query(".trustStore", containerNode)[0]);
             trustStore.set("store", trustStoresStore);
         },
-        _initFields: function (data, containerNode, metadata)
+        _initAuthenticationMethods: function (metadata, containerNode)
         {
             var attributes = metadata.getMetaData("AuthenticationProvider", "SimpleLDAP").attributes;
-            for (var name in attributes)
-            {
-                var domNode = query("." + name, containerNode)[0];
-                if (domNode)
-                {
-                    var widget = registry.byNode(domNode);
-                    if (widget)
-                    {
-                        if (widget instanceof dijit.form.CheckBox)
-                        {
-                            widget.set("checked", data[name]);
-                        }
-                        else
-                        {
-                            widget.set("value", data[name]);
-                        }
-                    }
-                }
-            }
+            var store = util.makeTypeStore(attributes.authenticationMethod.validValues);
+            var authenticationMethod = registry.byId("ldapAuthenticationMethod");
+            authenticationMethod.set("store", store);
+            authenticationMethod.on("change", function (value) {
+                registry.byId('ldapSearchUsername').set("required", (value === "SIMPLE"));
+            });
+        },
+        _initFields: function (data, containerNode, metadata)
+        {
+            util.applyToWidgets(containerNode,
+                "AuthenticationProvider",
+                "SimpleLDAP",
+                data,
+                metadata);
         }
     };
 });
diff --git a/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/simpleldap/show.js b/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/simpleldap/show.js
index 9e13956..096aa36 100644
--- a/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/simpleldap/show.js
+++ b/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/simpleldap/show.js
@@ -26,7 +26,10 @@ define(["qpid/common/util", "dojo/domReady!"], function (util)
         var attributes = data.parent.management.metadata.getMetaData("AuthenticationProvider", "SimpleLDAP").attributes;
         for (var name in attributes)
         {
-            this.fields.push(name);
+            if (attributes.hasOwnProperty(name))
+            {
+                this.fields.push(name);
+            }
         }
         util.buildUI(data.containerNode, data.parent, "authenticationprovider/simpleldap/show.html", this.fields, this);
     }
@@ -34,7 +37,7 @@ define(["qpid/common/util", "dojo/domReady!"], function (util)
     SimpleLdapAuthenticationProvider.prototype.update = function (data)
     {
         util.updateUI(data, this.fields, this);
-    }
+    };
 
     return SimpleLdapAuthenticationProvider;
 });
diff --git a/doc/java-broker/src/docbkx/security/Java-Broker-Security-Authentication-Providers-LDAP.xml b/doc/java-broker/src/docbkx/security/Java-Broker-Security-Authentication-Providers-LDAP.xml
index ed81c09..91ce9dc 100644
--- a/doc/java-broker/src/docbkx/security/Java-Broker-Security-Authentication-Providers-LDAP.xml
+++ b/doc/java-broker/src/docbkx/security/Java-Broker-Security-Authentication-Providers-LDAP.xml
@@ -57,6 +57,16 @@
                 certificate).</para>
         </listitem>
         <listitem>
+            <para><emphasis>Authentication method</emphasis> is a method of authentication to use on binding into LDAP
+                when <literal>bind without search</literal> mode is not selected.
+                Supported methods are NONE, SIMPLE, GSSAPI. The latter requires setting of <emphasis>Login Config Scope</emphasis>
+                which is a name of JAAS login module from JASS login configuration file specified using JVM system
+                property <emphasis>java.security.auth.login.config</emphasis> or Java security properties file. If
+                <emphasis>Login Config Scope</emphasis> is not specified with <literal>GSSAPI</literal>
+                <emphasis>Authentication method</emphasis>, the scope <emphasis>qpid-broker-j</emphasis> will be used.
+            </para>
+        </listitem>
+        <listitem>
             <para>Additional group information can be obtained from LDAP.
                 There are two common ways of representing group membership in LDAP.
                 <itemizedlist>
diff --git a/pom.xml b/pom.xml
index a76c4b8..e59d3ab 100644
--- a/pom.xml
+++ b/pom.xml
@@ -152,6 +152,7 @@
     <maven-jar-plugin-version>3.1.0</maven-jar-plugin-version>
     <maven-surefire-report-plugin-version>2.22.0</maven-surefire-report-plugin-version>
     <h2.version>1.4.199</h2.version>
+    <apache-directory-version>2.0.0-M23</apache-directory-version>
   </properties>
 
   <modules>
@@ -724,6 +725,23 @@
         <artifactId>maven-resolver-transport-http</artifactId>
         <version>${maven-resolver-version}</version>
       </dependency>
+      <!-- apacheds test dependency -->
+      <dependency>
+        <groupId>org.apache.directory.server</groupId>
+        <artifactId>apacheds-all</artifactId>
+        <version>${apache-directory-version}</version>
+        <scope>test</scope>
+        <exclusions>
+           <exclusion>
+            <groupId>org.apache.directory.shared</groupId>
+            <artifactId>shared-ldap-schema</artifactId>
+          </exclusion>
+          <exclusion>
+            <groupId>org.apache.directory.api</groupId>
+            <artifactId>api-ldap-schema-data</artifactId>
+          </exclusion>
+        </exclusions>
+      </dependency>
     </dependencies>
   </dependencyManagement>
 


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