Allow configuring additional ssl cipher suites for ldaps connections

LDAP configuration are often out of our scopes...

Change-Id: Id9cbce2e3de719e515b92c35a31e0bd4aa10d563
diff --git a/README.md b/README.md
index bb0f606..445e316 100644
--- a/README.md
+++ b/README.md
@@ -82,6 +82,8 @@
 ldapPort=636
 # to trust all certs, leave trustStore empty
 trustStore=truststore.jks
+# add ssl cipher suites if required as csv, e.g. TLS_RSA_WITH_AES_256_GCM_SHA384
+additionalCipherSuites=
 ldapBase=dc=example,dc=org
 sLoginDN=cn=admin,dc=example,dc=org
 pwd=adminpassword
diff --git a/full/src/main/java/de/ids_mannheim/korap/authentication/LdapAuth3.java b/full/src/main/java/de/ids_mannheim/korap/authentication/LdapAuth3.java
index 26a81fb..129843f 100644
--- a/full/src/main/java/de/ids_mannheim/korap/authentication/LdapAuth3.java
+++ b/full/src/main/java/de/ids_mannheim/korap/authentication/LdapAuth3.java
@@ -18,8 +18,7 @@
 import java.io.IOException;
 import java.net.UnknownHostException;
 import java.security.GeneralSecurityException;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.*;
 
 import static de.ids_mannheim.korap.server.EmbeddedLdapServer.loadProp;
 
@@ -73,7 +72,6 @@
         }
     }
 
-
     public static int login(String sUserDN, String sUserPwd, String ldapConfigFilename) throws LDAPException {
 
         sUserDN = Filter.encodeValue(sUserDN);
@@ -87,22 +85,22 @@
             return LDAP_AUTH_RINTERR;
         }
 
-        final Boolean ldapS = Boolean.parseBoolean(ldapConfig.getOrDefault("ldapS", "false"));
+        assert ldapConfig != null;
+        final boolean ldapS = Boolean.parseBoolean(ldapConfig.getOrDefault("ldapS", "false"));
         final String ldapHost = ldapConfig.getOrDefault("ldapHost", "localhost");
         final int ldapPort = Integer.parseInt(ldapConfig.getOrDefault("ldapPort", (ldapS ? "636" : "389")));
         final String ldapBase = ldapConfig.getOrDefault("ldapBase", "dc=example,dc=com");
         final String sLoginDN = ldapConfig.getOrDefault("sLoginDN", "cn=admin,dc=example,dc=com");
         final String ldapFilter = ldapConfig.getOrDefault("ldapFilter", "(&(|(&(mail=${username})(idsC2Password=${password}))(&(idsC2Profile=${username})(idsC2Password=${password})))(&(idsC2=TRUE)(|(idsStatus=1)(|(idsStatus=0)(xidsStatus=\00)))))");
         final String sPwd = ldapConfig.getOrDefault("pwd", "");
-        final String trustStorePath = ldapConfig.getOrDefault("trustStore", null);
-        final Boolean useEmbeddedServer = Boolean.parseBoolean(ldapConfig.getOrDefault("useEmbeddedServer", "false"));
+        final String trustStorePath = ldapConfig.getOrDefault("trustStore", "");
+        final String additionalCipherSuites = ldapConfig.getOrDefault("additionalCipherSuites", "");
+        final boolean useEmbeddedServer = Boolean.parseBoolean(ldapConfig.getOrDefault("useEmbeddedServer", "false"));
 
         if (useEmbeddedServer && EmbeddedLdapServer.server == null) {
             try {
                 EmbeddedLdapServer.start(ldapConfigFilename);
-            } catch (GeneralSecurityException e) {
-                throw new RuntimeException(e);
-            } catch (UnknownHostException e) {
+            } catch (GeneralSecurityException | UnknownHostException e) {
                 throw new RuntimeException(e);
             }
         }
@@ -122,7 +120,7 @@
         // LDAP Connection:
         if (DEBUGLOG) System.out.println("LDAPS " + ldapS);
 
-        LDAPConnection lc = null;
+        LDAPConnection lc;
 
         if (ldapS) {
             try {
@@ -132,22 +130,26 @@
                 } else {
                     sslUtil = new SSLUtil(new TrustAllTrustManager());
                 }
+                if (additionalCipherSuites != null && !additionalCipherSuites.isEmpty()) {
+                    addSSLCipherSuites(additionalCipherSuites);
+                }
                 SSLSocketFactory socketFactory = sslUtil.createSSLSocketFactory();
-                lc = new LDAPConnection(socketFactory, ldapHost, ldapPort);
+                lc = new LDAPConnection(socketFactory);
             } catch (GeneralSecurityException e) {
                 System.err.printf("Error: login: Connecting to LDAPS Server: failed: '%s'!\n", e);
-                return ldapTerminate(lc, LDAP_AUTH_RCONNECT);
+                return ldapTerminate(null, LDAP_AUTH_RCONNECT);
             }
         } else {
             lc = new LDAPConnection();
-            try {
-                lc.connect(ldapHost, ldapPort);
-                if (DEBUGLOG && ldapS) System.out.println("LDAPS Connection = OK\n");
-                if (DEBUGLOG && !ldapS) System.out.println("LDAP Connection = OK\n");
-            } catch (LDAPException e) {
-                System.err.printf("Error: login: Connecting to LDAP Server: failed: '%s'!\n", e);
-                return ldapTerminate(lc, LDAP_AUTH_RCONNECT);
-            }
+        }
+        try {
+            lc.connect(ldapHost, ldapPort);
+            if (DEBUGLOG && ldapS) System.out.println("LDAPS Connection = OK\n");
+            if (DEBUGLOG && !ldapS) System.out.println("LDAP Connection = OK\n");
+        } catch (LDAPException e) {
+            String fullStackTrace = org.apache.commons.lang.exception.ExceptionUtils.getFullStackTrace(e);
+            System.err.printf("Error: login: Connecting to LDAP Server: failed: '%s'!\n", fullStackTrace);
+            return ldapTerminate(lc, LDAP_AUTH_RCONNECT);
         }
 
 
@@ -157,7 +159,7 @@
             // bind to server:
             if (DEBUGLOG) System.out.printf("Binding with '%s' ...\n", sLoginDN);
             lc.bind(sLoginDN, sPwd);
-            if (DEBUGLOG) System.out.printf("Binding: OK.\n");
+            if (DEBUGLOG) System.out.print("Binding: OK.\n");
         } catch (LDAPException e) {
             System.err.printf("Error: login: Binding failed: '%s'!\n", e);
             return ldapTerminate(lc, LDAP_AUTH_RINTERR);
@@ -191,11 +193,21 @@
     public static int ldapTerminate(LDAPConnection lc, int ret) {
         if (DEBUGLOG) System.out.println("Terminating...");
 
-        lc.close(null);
+        if (lc != null) {
+            lc.close(null);
+        }
         if (DEBUGLOG) System.out.println("closing connection: done.\n");
         return ret;
     }
 
+    private static void addSSLCipherSuites(String ciphersCsv) {
+        // add e.g. TLS_RSA_WITH_AES_256_GCM_SHA384
+        Set<String> ciphers = new HashSet<>();
+        ciphers.addAll(SSLUtil.getEnabledSSLCipherSuites());
+        ciphers.addAll(Arrays.asList(ciphersCsv.split(", *")));
+        SSLUtil.setEnabledSSLCipherSuites(ciphers);
+    }
+
     @Override
     public TokenType getTokenType() {
         return TokenType.API;