From deec025971bc0e33f40479a27fa3e9687673b95d Mon Sep 17 00:00:00 2001
From: Michael Miko <michael.setiawan@rakuten.com>
Date: Fri, 29 Jul 2016 18:04:57 +0900
Subject: [PATCH 1/2] Add option to separate user search and user
 authentication

---
 .../marathon/plugin/auth/type/LDAPConfig.java | 16 ++++++
 .../marathon/plugin/auth/util/LDAPHelper.java | 52 ++++++++++++++-----
 .../marathon/plugin/auth/plugin-conf.json     |  2 +
 3 files changed, 57 insertions(+), 13 deletions(-)

diff --git a/src/main/java/io/containx/marathon/plugin/auth/type/LDAPConfig.java b/src/main/java/io/containx/marathon/plugin/auth/type/LDAPConfig.java
index f71cc6b..4e9acf8 100644
--- a/src/main/java/io/containx/marathon/plugin/auth/type/LDAPConfig.java
+++ b/src/main/java/io/containx/marathon/plugin/auth/type/LDAPConfig.java
@@ -25,6 +25,12 @@ public class LDAPConfig {
     @JsonProperty(required = false)
     private String groupSubTree = "ou=Group";
 
+    @JsonProperty(required = false)
+    private String bindUser = null;
+
+    @JsonProperty(required = false)
+    private String bindPassword = null;
+
 
     public LDAPConfig() {}
 
@@ -44,6 +50,14 @@ public void setBase(String base) {
         this.base = base;
     }
 
+    public String getBindUser() {
+        return bindUser;
+    }
+
+    public String getBindPassword() {
+        return bindPassword;
+    }
+
     public String getDn() {
         return dn;
     }
@@ -90,6 +104,8 @@ public String toString() {
                 "url='" + url + '\'' +
                 ", base='" + base + '\'' +
                 ", dn='" + dn + '\'' +
+                ", bindUser='" + bindUser + '\'' +
+                ", bindPassword='" + bindPassword + '\'' +
                 ", userSearch='" + userSearch + '\'' +
                 ", userSubTree='" + userSubTree + '\'' +
                 ", groupSearch='" + groupSearch + '\'' +
diff --git a/src/main/java/io/containx/marathon/plugin/auth/util/LDAPHelper.java b/src/main/java/io/containx/marathon/plugin/auth/util/LDAPHelper.java
index 7829408..2904471 100644
--- a/src/main/java/io/containx/marathon/plugin/auth/util/LDAPHelper.java
+++ b/src/main/java/io/containx/marathon/plugin/auth/util/LDAPHelper.java
@@ -20,7 +20,7 @@ public final class LDAPHelper {
     private static final Logger LOGGER = LoggerFactory.getLogger(LDAPHelper.class);
 
 
-    public static Set<String> validate(String username, String password, LDAPConfig config ) {
+    public static Set<String> validate(String username, String userPassword, LDAPConfig config) {
 
         if (config == null) {
             LOGGER.warn("LDAP Configuration not defined.  Skipping LDAP authentication");
@@ -30,22 +30,31 @@ public static Set<String> validate(String username, String password, LDAPConfig
         DirContext context = null;
 
         try {
-            String dn = new StringBuilder(config.getDn().replace("{username}", username))
-                    .append(",")
-                    .append(config.getUserSubTree() != null ? config.getUserSubTree() + "," : "")
-                    .append(config.getBase())
-                    .toString();
+            String dn = "";
+            String bindUser = config.getBindUser();
+            String bindPassword = userPassword;
+
+            if(bindUser != null) {
+                dn = bindUser;
+                bindPassword = config.getBindPassword();
+            } else {
+                dn = new StringBuilder(config.getDn().replace("{username}", username))
+                        .append(",")
+                        .append(config.getUserSubTree() != null ? config.getUserSubTree() + "," : "")
+                        .append(config.getBase())
+                        .toString();
+            }
 
-            LOGGER.debug("LDAP trying to connect as {} on {}", dn, config.getUrl());
+            LOGGER.error("LDAP trying to connect as {} on {}", dn, config.getUrl());
             Hashtable<String, String> env = new Hashtable<>();
             env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
             env.put(Context.PROVIDER_URL, config.getUrl());
             env.put(Context.SECURITY_PRINCIPAL, dn);
-            env.put(Context.SECURITY_CREDENTIALS, password);
+            env.put(Context.SECURITY_CREDENTIALS, bindPassword);
             context = new InitialDirContext(env);
 
             // if an exception wasn't raised, then we managed to bind to the directory
-            LOGGER.info("LDAP Auth succeeded for user {}", dn);
+            LOGGER.info("LDAP Bind succeeded for user {}", dn);
 
             SearchControls controls = new SearchControls();
             controls.setSearchScope(SUBTREE_SCOPE);
@@ -59,7 +68,7 @@ public static Set<String> validate(String username, String password, LDAPConfig
                         .append(",").append(searchContext)
                         .toString();
             }
-            LOGGER.debug("LDAP searching {} in {}", searchString, searchContext);
+            LOGGER.error("LDAP searching {} in {}", searchString, searchContext);
             NamingEnumeration<SearchResult> renum =
                     context.search(searchContext, searchString, controls);
 
@@ -69,7 +78,24 @@ public static Set<String> validate(String username, String password, LDAPConfig
             }
 
             SearchResult result = renum.next();
-            LOGGER.debug("LDAP user search found {}", result.toString());
+            LOGGER.error("LDAP user search found {}", result.toString());
+
+            if(bindUser != null) {
+                Attribute realDN = result.getAttributes().get("distinguishedname");
+                dn = realDN.get(0).toString();
+
+                if(userPassword == null || userPassword.isEmpty()) {
+                    return null;
+                }
+
+                LOGGER.error("Authenticate with DN {}", dn);
+                env.put(Context.SECURITY_PRINCIPAL, dn);
+                env.put(Context.SECURITY_CREDENTIALS, userPassword);
+
+                context = new InitialDirContext(env);
+
+                LOGGER.info("LDAP Auth succeeded for user {}", dn);
+            }
 
             // search group memberships as user attributes
             Attribute memberOf = result.getAttributes().get("memberOf");
@@ -96,14 +122,14 @@ public static Set<String> validate(String username, String password, LDAPConfig
                             .append(",").append(searchContext)
                             .toString();
                 }
-                LOGGER.debug("LDAP searching for group membership {} in {}", searchString, searchContext);
+                LOGGER.error("LDAP searching for group membership {} in {}", searchString, searchContext);
                 renum = context.search(searchContext, searchString, controls);
 
                 while (renum.hasMore()) {
                     SearchResult group = renum.next();
                     String groupName = group.getAttributes().get("cn").get().toString();
                     memberships.add(groupName);
-                    LOGGER.debug("LDAP found {} in group {}", username, groupName);
+                    LOGGER.error("LDAP found {} in group {}", username, groupName);
                 }
 
             }
diff --git a/src/main/resources/io/containx/marathon/plugin/auth/plugin-conf.json b/src/main/resources/io/containx/marathon/plugin/auth/plugin-conf.json
index ab3eb8a..813d345 100644
--- a/src/main/resources/io/containx/marathon/plugin/auth/plugin-conf.json
+++ b/src/main/resources/io/containx/marathon/plugin/auth/plugin-conf.json
@@ -12,6 +12,8 @@
                     "url": "ldap://my.ldapserver.local:389",
                     "base": "dc=example,dc=com",
                     "dn": "uid={username}",
+                    "bindUser": "usernameToBind",
+                    "bindPassword": "passwordToBind",
                     "userSearch": "(&(uid={username})(objectClass=inetOrgPerson))",
                     "userSubTree": "ou=People",
                     "groupSearch": "(&(memberUid={username})(objectClass=posixGroup))",

From e0bb2e46d7e5c7e2e5eba59302ecfed0ffdf0cf9 Mon Sep 17 00:00:00 2001
From: Michael Miko <michael.setiawan@rakuten.com>
Date: Fri, 29 Jul 2016 18:07:15 +0900
Subject: [PATCH 2/2] Putting back logger

---
 .../marathon/plugin/auth/util/LDAPHelper.java        | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/main/java/io/containx/marathon/plugin/auth/util/LDAPHelper.java b/src/main/java/io/containx/marathon/plugin/auth/util/LDAPHelper.java
index 2904471..8519eed 100644
--- a/src/main/java/io/containx/marathon/plugin/auth/util/LDAPHelper.java
+++ b/src/main/java/io/containx/marathon/plugin/auth/util/LDAPHelper.java
@@ -45,7 +45,7 @@ public static Set<String> validate(String username, String userPassword, LDAPCon
                         .toString();
             }
 
-            LOGGER.error("LDAP trying to connect as {} on {}", dn, config.getUrl());
+            LOGGER.debug("LDAP trying to connect as {} on {}", dn, config.getUrl());
             Hashtable<String, String> env = new Hashtable<>();
             env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
             env.put(Context.PROVIDER_URL, config.getUrl());
@@ -68,7 +68,7 @@ public static Set<String> validate(String username, String userPassword, LDAPCon
                         .append(",").append(searchContext)
                         .toString();
             }
-            LOGGER.error("LDAP searching {} in {}", searchString, searchContext);
+            LOGGER.debug("LDAP searching {} in {}", searchString, searchContext);
             NamingEnumeration<SearchResult> renum =
                     context.search(searchContext, searchString, controls);
 
@@ -78,7 +78,7 @@ public static Set<String> validate(String username, String userPassword, LDAPCon
             }
 
             SearchResult result = renum.next();
-            LOGGER.error("LDAP user search found {}", result.toString());
+            LOGGER.debug("LDAP user search found {}", result.toString());
 
             if(bindUser != null) {
                 Attribute realDN = result.getAttributes().get("distinguishedname");
@@ -88,7 +88,7 @@ public static Set<String> validate(String username, String userPassword, LDAPCon
                     return null;
                 }
 
-                LOGGER.error("Authenticate with DN {}", dn);
+                LOGGER.debug("Authenticate with DN {}", dn);
                 env.put(Context.SECURITY_PRINCIPAL, dn);
                 env.put(Context.SECURITY_CREDENTIALS, userPassword);
 
@@ -122,14 +122,14 @@ public static Set<String> validate(String username, String userPassword, LDAPCon
                             .append(",").append(searchContext)
                             .toString();
                 }
-                LOGGER.error("LDAP searching for group membership {} in {}", searchString, searchContext);
+                LOGGER.debug("LDAP searching for group membership {} in {}", searchString, searchContext);
                 renum = context.search(searchContext, searchString, controls);
 
                 while (renum.hasMore()) {
                     SearchResult group = renum.next();
                     String groupName = group.getAttributes().get("cn").get().toString();
                     memberships.add(groupName);
-                    LOGGER.error("LDAP found {} in group {}", username, groupName);
+                    LOGGER.debug("LDAP found {} in group {}", username, groupName);
                 }
 
             }