Browse Source

LDAP: Adds back support for single bind. (#17999)

Leonard Gram 6 years ago
parent
commit
25506829be
2 changed files with 54 additions and 8 deletions
  1. 22 8
      pkg/services/ldap/ldap.go
  2. 32 0
      pkg/services/ldap/ldap_login_test.go

+ 22 - 8
pkg/services/ldap/ldap.go

@@ -140,15 +140,19 @@ func (server *Server) Login(query *models.LoginUserQuery) (
 	*models.ExternalUserInfo, error,
 	*models.ExternalUserInfo, error,
 ) {
 ) {
 	var err error
 	var err error
+	var authAndBind bool
 
 
-	// Do we need to authenticate the "admin" user first?
-	// Admin user should have access for the user search in LDAP server
+	// Check if we can use a search user
 	if server.shouldAuthAdmin() {
 	if server.shouldAuthAdmin() {
 		if err := server.AuthAdmin(); err != nil {
 		if err := server.AuthAdmin(); err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
-
-		// Or if anyone can perform the search in LDAP?
+	} else if server.shouldSingleBind() {
+		authAndBind = true
+		err = server.Auth(server.singleBindDN(query.Username), query.Password)
+		if err != nil {
+			return nil, err
+		}
 	} else {
 	} else {
 		err := server.Connection.UnauthenticatedBind(server.Config.BindDN)
 		err := server.Connection.UnauthenticatedBind(server.Config.BindDN)
 		if err != nil {
 		if err != nil {
@@ -173,15 +177,25 @@ func (server *Server) Login(query *models.LoginUserQuery) (
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	// Authenticate user
-	err = server.Auth(user.AuthId, query.Password)
-	if err != nil {
-		return nil, err
+	if !authAndBind {
+		// Authenticate user
+		err = server.Auth(user.AuthId, query.Password)
+		if err != nil {
+			return nil, err
+		}
 	}
 	}
 
 
 	return user, nil
 	return user, nil
 }
 }
 
 
+func (server *Server) singleBindDN(username string) string {
+	return fmt.Sprintf(server.Config.BindDN, username)
+}
+
+func (server *Server) shouldSingleBind() bool {
+	return strings.Contains(server.Config.BindDN, "%s")
+}
+
 // getUsersIteration is a helper function for Users() method.
 // getUsersIteration is a helper function for Users() method.
 // It divides the users by equal parts for the anticipated requests
 // It divides the users by equal parts for the anticipated requests
 func getUsersIteration(logins []string, fn func(int, int) error) error {
 func getUsersIteration(logins []string, fn func(int, int) error) error {

+ 32 - 0
pkg/services/ldap/ldap_login_test.go

@@ -198,5 +198,37 @@ func TestLDAPLogin(t *testing.T) {
 			So(username, ShouldEqual, "test")
 			So(username, ShouldEqual, "test")
 			So(password, ShouldEqual, "pwd")
 			So(password, ShouldEqual, "pwd")
 		})
 		})
+		Convey("Should bind with user if %s exists in the bind_dn", func() {
+			connection := &MockConnection{}
+			entry := ldap.Entry{
+				DN: "test",
+			}
+			connection.setSearchResult(&ldap.SearchResult{Entries: []*ldap.Entry{&entry}})
+
+			authBindUser := ""
+			authBindPassword := ""
+
+			connection.BindProvider = func(name, pass string) error {
+				authBindUser = name
+				authBindPassword = pass
+				return nil
+			}
+			server := &Server{
+				Config: &ServerConfig{
+					BindDN:        "cn=%s,ou=users,dc=grafana,dc=org",
+					SearchBaseDNs: []string{"BaseDNHere"},
+				},
+				Connection: connection,
+				log:        log.New("test-logger"),
+			}
+
+			_, err := server.Login(defaultLogin)
+
+			So(err, ShouldBeNil)
+
+			So(authBindUser, ShouldEqual, "cn=user,ou=users,dc=grafana,dc=org")
+			So(authBindPassword, ShouldEqual, "pwd")
+			So(connection.BindCalled, ShouldBeTrue)
+		})
 	})
 	})
 }
 }