Add test for DIGEST-MD5 SASL auth and switch to newer OpenLDAP docker image
diff --git a/Jenkinsfile b/Jenkinsfile
index b00de7f..a70db52 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -37,7 +37,7 @@
       }
       steps {
         script {
-          docker.image('osixia/openldap:1.3.0').withRun('-e LDAP_TLS_VERIFY_CLIENT=never') { openldap ->
+          docker.image('osixia/openldap:1.5.0').withRun('-e LDAP_TLS_VERIFY_CLIENT=never') { openldap ->
             docker.image('389ds/dirsrv').withRun('-e DS_DM_PASSWORD=admin', 'bash -c "set -m; /usr/lib/dirsrv/dscontainer -r & while ! /usr/lib/dirsrv/dscontainer -H; do sleep 5; done; sleep 5; /usr/sbin/dsconf localhost backend create --suffix dc=example,dc=org --be-name example; fg"') { fedora389ds ->
               docker.image('apachedirectory/maven-build:jdk-8').inside("--link=${openldap.id}:openldap -e OPENLDAP_HOST=openldap -e OPENLDAP_PORT=389 -e OPENLDAP_PORT_SSL=636 --link=${fedora389ds.id}:fedora389ds -e FEDORA_389DS_HOST=fedora389ds -e FEDORA_389DS_PORT=3389 -e FEDORA_389DS_PORT_SSL=3636") {
                 sh 'export DISPLAY=:99; env; ps aux'
@@ -64,7 +64,7 @@
           }
           steps {
             script {
-              docker.image('osixia/openldap:1.3.0').withRun('-e LDAP_TLS_VERIFY_CLIENT=never') { openldap ->
+              docker.image('osixia/openldap:1.5.0').withRun('-e LDAP_TLS_VERIFY_CLIENT=never') { openldap ->
                 docker.image('389ds/dirsrv').withRun('-e DS_DM_PASSWORD=admin', 'bash -c "set -m; /usr/lib/dirsrv/dscontainer -r & while ! /usr/lib/dirsrv/dscontainer -H; do sleep 5; done; sleep 5; /usr/sbin/dsconf localhost backend create --suffix dc=example,dc=org --be-name example; fg"') { fedora389ds ->
                   docker.image('apachedirectory/maven-build:jdk-11').inside("--link=${openldap.id}:openldap -e OPENLDAP_HOST=openldap -e OPENLDAP_PORT=389 -e OPENLDAP_PORT_SSL=636 --link=${fedora389ds.id}:fedora389ds -e FEDORA_389DS_HOST=fedora389ds -e FEDORA_389DS_PORT=3389 -e FEDORA_389DS_PORT_SSL=3636") {
                     sh 'export DISPLAY=:99; mvn -V -U -f pom-first.xml clean install && mvn -V clean install -Dorg.eclipse.swtbot.search.timeout=20000 -Denable-ui-tests'
@@ -91,7 +91,7 @@
           }
           steps {
             script {
-              docker.image('osixia/openldap:1.3.0').withRun('-e LDAP_TLS_VERIFY_CLIENT=never') { openldap ->
+              docker.image('osixia/openldap:1.5.0').withRun('-e LDAP_TLS_VERIFY_CLIENT=never') { openldap ->
                 docker.image('389ds/dirsrv').withRun('-e DS_DM_PASSWORD=admin', 'bash -c "set -m; /usr/lib/dirsrv/dscontainer -r & while ! /usr/lib/dirsrv/dscontainer -H; do sleep 5; done; sleep 5; /usr/sbin/dsconf localhost backend create --suffix dc=example,dc=org --be-name example; fg"') { fedora389ds ->
                   docker.image('apachedirectory/maven-build:jdk-17').inside("--link=${openldap.id}:openldap -e OPENLDAP_HOST=openldap -e OPENLDAP_PORT=389 -e OPENLDAP_PORT_SSL=636 --link=${fedora389ds.id}:fedora389ds -e FEDORA_389DS_HOST=fedora389ds -e FEDORA_389DS_PORT=3389 -e FEDORA_389DS_PORT_SSL=3636") {
                     sh 'export DISPLAY=:99; mvn -V -U -f pom-first.xml clean install && mvn -V clean install -Dorg.eclipse.swtbot.search.timeout=20000 -Denable-ui-tests'
diff --git a/tests/test.integration.core/src/main/java/org/apache/directory/studio/test/integration/junit5/ApacheDirectoryServer.java b/tests/test.integration.core/src/main/java/org/apache/directory/studio/test/integration/junit5/ApacheDirectoryServer.java
index 3f0d9af..ade8ddf 100644
--- a/tests/test.integration.core/src/main/java/org/apache/directory/studio/test/integration/junit5/ApacheDirectoryServer.java
+++ b/tests/test.integration.core/src/main/java/org/apache/directory/studio/test/integration/junit5/ApacheDirectoryServer.java
@@ -24,6 +24,8 @@
 import static org.apache.directory.studio.test.integration.junit5.Constants.LOCALHOST;
 
 import java.io.File;
+import java.util.Collections;
+import java.util.stream.Collectors;
 
 import org.apache.directory.server.core.api.DirectoryService;
 import org.apache.directory.server.core.api.partition.Partition;
@@ -32,6 +34,9 @@
 import org.apache.directory.server.ldap.handlers.extended.PwdModifyHandler;
 import org.apache.directory.server.ldap.handlers.extended.StartTlsHandler;
 import org.apache.directory.server.ldap.handlers.extended.WhoAmIHandler;
+import org.apache.directory.server.ldap.handlers.sasl.SimpleMechanismHandler;
+import org.apache.directory.server.ldap.handlers.sasl.cramMD5.CramMd5MechanismHandler;
+import org.apache.directory.server.ldap.handlers.sasl.digestMD5.DigestMd5MechanismHandler;
 import org.apache.directory.server.protocol.shared.transport.TcpTransport;
 import org.apache.directory.server.protocol.shared.transport.Transport;
 import org.apache.mina.util.AvailablePortFinder;
@@ -77,6 +82,11 @@
             partition.initialize();
             service.addPartition( partition );
             service.getSchemaManager().enable( "nis", "krb5kdc" );
+            service.getInterceptor( "passwordHashingInterceptor" );
+            service.setInterceptors( service.getInterceptors().stream()
+                .filter( i -> !i.getName().equals( "ConfigurableHashingInterceptor" ) )
+                .collect( Collectors.toList() ) );
+            System.out.println( service.getInterceptors() );
 
             server = new LdapServer();
             server.setDirectoryService( service );
@@ -85,6 +95,13 @@
             Transport ldaps = new TcpTransport( portSSL );
             ldaps.setEnableSSL( true );
             server.addTransports( ldaps );
+
+            server.addSaslMechanismHandler( "SIMPLE", new SimpleMechanismHandler() );
+            server.addSaslMechanismHandler( "DIGEST-MD5", new DigestMd5MechanismHandler() );
+            server.setSaslRealms( Collections.singletonList( "EXAMPLE.ORG" ) );
+            server.setSaslHost( getHost() );
+            server.setSearchBaseDn( TestFixture.CONTEXT_DN.getName() );
+
             server.addExtendedOperationHandler( new StartTlsHandler() );
             server.addExtendedOperationHandler( new PwdModifyHandler() );
             server.addExtendedOperationHandler( new WhoAmIHandler() );
diff --git a/tests/test.integration.core/src/main/resources/org/apache/directory/studio/test/integration/junit5/OpenLdapConfig.ldif b/tests/test.integration.core/src/main/resources/org/apache/directory/studio/test/integration/junit5/OpenLdapConfig.ldif
index f28f338..9fe06a5 100644
--- a/tests/test.integration.core/src/main/resources/org/apache/directory/studio/test/integration/junit5/OpenLdapConfig.ldif
+++ b/tests/test.integration.core/src/main/resources/org/apache/directory/studio/test/integration/junit5/OpenLdapConfig.ldif
@@ -23,3 +23,21 @@
 olcAccess: {1}to dn.exact="" by * read
 olcAccess: {2}to dn.base="cn=Subschema" by dn.exact="uid=user.1,ou=users,dc=example,dc=org" none by * read
 -
+
+dn: olcDatabase={1}mdb,cn=config
+changetype: modify
+replace: olcAccess
+olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * break
+olcAccess: {1}to attrs=userPassword,shadowLastChange by self write by dn="cn=a dmin,dc=example,dc=org" write by anonymous auth by * none
+olcAccess: {2}to * by self read by dn="cn=admin,dc=example,dc=org" write by anonymous auth by * none
+-
+
+dn: cn=config
+changetype: modify
+replace: olcAuthzRegexp
+olcAuthzRegexp: uid=([^,]*),cn=digest-md5,cn=auth uid=$1,ou=users,dc=example,dc=org
+-
+replace: olcSaslSecProps
+olcSaslSecProps: noplain,noanonymous,minssf=128
+-
+
diff --git a/tests/test.integration.ui/src/main/java/org/apache/directory/studio/test/integration/ui/NewConnectionWizardTest.java b/tests/test.integration.ui/src/main/java/org/apache/directory/studio/test/integration/ui/NewConnectionWizardTest.java
index 279399d..93df03f 100644
--- a/tests/test.integration.ui/src/main/java/org/apache/directory/studio/test/integration/ui/NewConnectionWizardTest.java
+++ b/tests/test.integration.ui/src/main/java/org/apache/directory/studio/test/integration/ui/NewConnectionWizardTest.java
@@ -34,12 +34,16 @@
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 
+import org.apache.directory.api.ldap.model.constants.SaslQoP;
+import org.apache.directory.api.ldap.model.constants.SaslSecurityStrength;
 import org.apache.directory.studio.connection.core.Connection;
 import org.apache.directory.studio.connection.core.ConnectionCorePlugin;
 import org.apache.directory.studio.connection.core.ConnectionManager;
 import org.apache.directory.studio.connection.core.ConnectionParameter.AuthenticationMethod;
 import org.apache.directory.studio.test.integration.junit5.Constants;
+import org.apache.directory.studio.test.integration.junit5.LdapServerType;
 import org.apache.directory.studio.test.integration.junit5.LdapServersSource;
+import org.apache.directory.studio.test.integration.junit5.LdapServersSource.Mode;
 import org.apache.directory.studio.test.integration.junit5.TestLdapServer;
 import org.apache.directory.studio.test.integration.ui.bots.NewConnectionWizardBot;
 import org.apache.mina.util.AvailablePortFinder;
@@ -477,7 +481,7 @@
      */
     @ParameterizedTest
     @LdapServersSource
-    public void testCheckAuthenticationButtonOK( TestLdapServer server )
+    public void testCheckAuthenticationButtonSimpleAuthOK( TestLdapServer server )
     {
         // enter connection parameter
         wizardBot.typeConnectionName( getConnectionName() );
@@ -502,7 +506,7 @@
      */
     @ParameterizedTest
     @LdapServersSource
-    public void testCheckAuthenticationButtonNotOK( TestLdapServer server )
+    public void testCheckAuthenticationButtonSimpleAuthNotOK( TestLdapServer server )
     {
         // enter connection parameter
         wizardBot.typeConnectionName( getConnectionName() );
@@ -522,4 +526,96 @@
         wizardBot.clickCancelButton();
     }
 
+
+    /**
+     * Tests the "Check Authentication" button.
+     */
+    @ParameterizedTest
+    @LdapServersSource(mode = Mode.All, except = LdapServerType.Fedora389ds)
+    public void testCheckAuthenticationButtonDigestMD5OK( TestLdapServer server )
+    {
+        // enter connection parameter
+        wizardBot.typeConnectionName( getConnectionName() );
+        wizardBot.typeHost( server.getHost() );
+        wizardBot.typePort( server.getPort() );
+        wizardBot.clickNextButton();
+
+        // enter correct authentication parameter
+        wizardBot.selectDigestMD5Authentication();
+        wizardBot.typeUser( "user.8" );
+        wizardBot.typePassword( "password" );
+        if ( server.getType() == LdapServerType.ApacheDS )
+        {
+            wizardBot.typeRealm( "EXAMPLE.ORG" );
+        }
+        wizardBot.selectQualityOfProtection( SaslQoP.AUTH_CONF );
+        wizardBot.selectProtectionStrength( SaslSecurityStrength.HIGH );
+
+        // click "Check Network Parameter" button
+        String result = wizardBot.clickCheckAuthenticationButton();
+        assertNull( result, "Expected OK" );
+
+        wizardBot.clickCancelButton();
+    }
+
+
+    /**
+     * Tests the "Check Authentication" button.
+     */
+    @ParameterizedTest
+    @LdapServersSource(only = LdapServerType.OpenLdap)
+    public void testCheckAuthenticationButtonDigestMD5OKTooWeek( TestLdapServer server )
+    {
+        // enter connection parameter
+        wizardBot.typeConnectionName( getConnectionName() );
+        wizardBot.typeHost( server.getHost() );
+        wizardBot.typePort( server.getPort() );
+        wizardBot.clickNextButton();
+
+        // enter correct authentication parameter
+        wizardBot.selectDigestMD5Authentication();
+        wizardBot.typeUser( "user.8" );
+        wizardBot.typePassword( "password" );
+        wizardBot.selectQualityOfProtection( SaslQoP.AUTH );
+        wizardBot.selectProtectionStrength( SaslSecurityStrength.LOW );
+
+        // click "Check Network Parameter" button
+        String result = wizardBot.clickCheckAuthenticationButton();
+        assertThat( result, containsString( "DIGEST-MD5: No common protection layer between client and server" ) );
+
+        wizardBot.clickCancelButton();
+    }
+
+
+    /**
+     * Tests the "Check Authentication" button.
+     */
+    @ParameterizedTest
+    @LdapServersSource(mode = Mode.All, except = LdapServerType.Fedora389ds)
+    public void testCheckAuthenticationButtonDigestMD5NotOKWrongPassword( TestLdapServer server )
+    {
+        // enter connection parameter
+        wizardBot.typeConnectionName( getConnectionName() );
+        wizardBot.typeHost( server.getHost() );
+        wizardBot.typePort( server.getPort() );
+        wizardBot.clickNextButton();
+
+        // enter correct authentication parameter
+        wizardBot.selectDigestMD5Authentication();
+        wizardBot.typeUser( "user.8" );
+        wizardBot.typePassword( "wrong" );
+        if ( server.getType() == LdapServerType.ApacheDS )
+        {
+            wizardBot.typeRealm( "EXAMPLE.ORG" );
+        }
+        wizardBot.selectQualityOfProtection( SaslQoP.AUTH_CONF );
+        wizardBot.selectProtectionStrength( SaslSecurityStrength.HIGH );
+
+        // click "Check Network Parameter" button
+        String result = wizardBot.clickCheckAuthenticationButton();
+        assertThat( result, containsString( "[LDAP result code 49 - invalidCredentials]" ) );
+
+        wizardBot.clickCancelButton();
+    }
+
 }
diff --git a/tests/test.integration.ui/src/main/java/org/apache/directory/studio/test/integration/ui/bots/NewConnectionWizardBot.java b/tests/test.integration.ui/src/main/java/org/apache/directory/studio/test/integration/ui/bots/NewConnectionWizardBot.java
index e39f4f8..029b6c1 100644
--- a/tests/test.integration.ui/src/main/java/org/apache/directory/studio/test/integration/ui/bots/NewConnectionWizardBot.java
+++ b/tests/test.integration.ui/src/main/java/org/apache/directory/studio/test/integration/ui/bots/NewConnectionWizardBot.java
@@ -20,6 +20,8 @@
 package org.apache.directory.studio.test.integration.ui.bots;
 
 
+import org.apache.directory.api.ldap.model.constants.SaslQoP;
+import org.apache.directory.api.ldap.model.constants.SaslSecurityStrength;
 import org.apache.directory.studio.ldapbrowser.core.BrowserCoreMessages;
 import org.apache.directory.studio.test.integration.ui.utils.JobWatcher;
 import org.eclipse.swtbot.swt.finder.widgets.SWTBotCombo;
@@ -41,6 +43,8 @@
     private static final String GET_BASE_DNS_FROM_ROOT_DSE = "Get base DNs from Root DSE";
     private static final String SAVE_PASSWORD = "Save password";
     private static final String SASL_REALM = "SASL Realm:";
+    private static final String SASL_QUALITY_OF_PROTECTION = "Quality of Protection:";
+    private static final String SASL_PROTECTION_STRENGH = "Protection Strength:";
     private static final String BIND_PASSWORD = "Bind password:";
     private static final String BIND_DN_OR_USER = "Bind DN or user:";
     private static final String CRAM_MD5_SASL = "CRAM-MD5 (SASL)";
@@ -208,8 +212,44 @@
 
     public void typeRealm( String realm )
     {
-        SWTBotCombo dnCombo = bot.comboBoxWithLabel( SASL_REALM );
-        dnCombo.setText( realm );
+        SWTBotCombo combo = bot.comboBoxWithLabel( SASL_REALM );
+        combo.setText( realm );
+    }
+
+
+    public void selectQualityOfProtection( SaslQoP saslQoP )
+    {
+        SWTBotCombo combo = bot.comboBoxWithLabel( SASL_QUALITY_OF_PROTECTION );
+        switch ( saslQoP )
+        {
+            case AUTH:
+                combo.setSelection( 0 );
+                break;
+            case AUTH_INT:
+                combo.setSelection( 1 );
+                break;
+            case AUTH_CONF:
+                combo.setSelection( 2 );
+                break;
+        }
+    }
+
+
+    public void selectProtectionStrength( SaslSecurityStrength saslSecurityStrength )
+    {
+        SWTBotCombo combo = bot.comboBoxWithLabel( SASL_PROTECTION_STRENGH );
+        switch ( saslSecurityStrength )
+        {
+            case HIGH:
+                combo.setSelection( 0 );
+                break;
+            case MEDIUM:
+                combo.setSelection( 1 );
+                break;
+            case LOW:
+                combo.setSelection( 2 );
+                break;
+        }
     }