浏览代码

LDAP: Adds bind before searching LDAP for non-login cases. (#18023)

Leonard Gram 6 年之前
父节点
当前提交
5d3a60d46e

+ 27 - 9
pkg/services/ldap/ldap.go

@@ -31,7 +31,8 @@ type IConnection interface {
 type IServer interface {
 	Login(*models.LoginUserQuery) (*models.ExternalUserInfo, error)
 	Users([]string) ([]*models.ExternalUserInfo, error)
-	Auth(string, string) error
+	Bind() error
+	UserBind(string, string) error
 	Dial() error
 	Close()
 }
@@ -43,6 +44,23 @@ type Server struct {
 	log        log.Logger
 }
 
+// Bind authenticates the connection with the LDAP server
+// - with the username and password setup in the config
+// - or, anonymously
+func (server *Server) Bind() error {
+	if server.shouldAuthAdmin() {
+		if err := server.AuthAdmin(); err != nil {
+			return err
+		}
+	} else {
+		err := server.Connection.UnauthenticatedBind(server.Config.BindDN)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
 // UsersMaxRequest is a max amount of users we can request via Users().
 // Since many LDAP servers has limitations
 // on how much items can we return in one request
@@ -149,7 +167,7 @@ func (server *Server) Login(query *models.LoginUserQuery) (
 		}
 	} else if server.shouldSingleBind() {
 		authAndBind = true
-		err = server.Auth(server.singleBindDN(query.Username), query.Password)
+		err = server.UserBind(server.singleBindDN(query.Username), query.Password)
 		if err != nil {
 			return nil, err
 		}
@@ -179,7 +197,7 @@ func (server *Server) Login(query *models.LoginUserQuery) (
 
 	if !authAndBind {
 		// Authenticate user
-		err = server.Auth(user.AuthId, query.Password)
+		err = server.UserBind(user.AuthId, query.Password)
 		if err != nil {
 			return nil, err
 		}
@@ -380,9 +398,9 @@ func (server *Server) shouldAuthAdmin() bool {
 	return server.Config.BindPassword != ""
 }
 
-// Auth authentificates user in LDAP
-func (server *Server) Auth(username, password string) error {
-	err := server.auth(username, password)
+// UserBind authenticates the connection with the LDAP server
+func (server *Server) UserBind(username, password string) error {
+	err := server.userBind(username, password)
 	if err != nil {
 		server.log.Error(
 			fmt.Sprintf("Cannot authentificate user %s in LDAP", username),
@@ -397,7 +415,7 @@ func (server *Server) Auth(username, password string) error {
 
 // AuthAdmin authentificates LDAP admin user
 func (server *Server) AuthAdmin() error {
-	err := server.auth(server.Config.BindDN, server.Config.BindPassword)
+	err := server.userBind(server.Config.BindDN, server.Config.BindPassword)
 	if err != nil {
 		server.log.Error(
 			"Cannot authentificate admin user in LDAP",
@@ -410,8 +428,8 @@ func (server *Server) AuthAdmin() error {
 	return nil
 }
 
-// auth is helper for several types of LDAP authentification
-func (server *Server) auth(path, password string) error {
+// userBind authenticates the connection with the LDAP server
+func (server *Server) userBind(path, password string) error {
 	err := server.Connection.Bind(path, password)
 	if err != nil {
 		if ldapErr, ok := err.(*ldap.Error); ok {

+ 1 - 1
pkg/services/ldap/ldap_login_test.go

@@ -19,7 +19,7 @@ func TestLDAPLogin(t *testing.T) {
 	}
 
 	Convey("Login()", t, func() {
-		Convey("Should get invalid credentials when auth fails", func() {
+		Convey("Should get invalid credentials when userBind fails", func() {
 			connection := &MockConnection{}
 			entry := ldap.Entry{}
 			result := ldap.SearchResult{Entries: []*ldap.Entry{&entry}}

+ 2 - 2
pkg/services/ldap/ldap_private_test.go

@@ -145,7 +145,7 @@ func TestLDAPPrivateMethods(t *testing.T) {
 	})
 
 	Convey("shouldAuthAdmin()", t, func() {
-		Convey("it should require admin auth", func() {
+		Convey("it should require admin userBind", func() {
 			server := &Server{
 				Config: &ServerConfig{
 					BindPassword: "test",
@@ -156,7 +156,7 @@ func TestLDAPPrivateMethods(t *testing.T) {
 			So(result, ShouldBeTrue)
 		})
 
-		Convey("it should not require admin auth", func() {
+		Convey("it should not require admin userBind", func() {
 			server := &Server{
 				Config: &ServerConfig{
 					BindPassword: "",

+ 3 - 3
pkg/services/ldap/ldap_test.go

@@ -102,7 +102,7 @@ func TestPublicAPI(t *testing.T) {
 		})
 	})
 
-	Convey("Auth()", t, func() {
+	Convey("UserBind()", t, func() {
 		Convey("Should use provided DN and password", func() {
 			connection := &MockConnection{}
 			var actualUsername, actualPassword string
@@ -119,7 +119,7 @@ func TestPublicAPI(t *testing.T) {
 			}
 
 			dn := "cn=user,ou=users,dc=grafana,dc=org"
-			err := server.Auth(dn, "pwd")
+			err := server.UserBind(dn, "pwd")
 
 			So(err, ShouldBeNil)
 			So(actualUsername, ShouldEqual, dn)
@@ -141,7 +141,7 @@ func TestPublicAPI(t *testing.T) {
 				},
 				log: log.New("test-logger"),
 			}
-			err := server.Auth("user", "pwd")
+			err := server.UserBind("user", "pwd")
 			So(err, ShouldEqual, expected)
 		})
 	})

+ 8 - 0
pkg/services/multildap/multildap.go

@@ -109,6 +109,10 @@ func (multiples *MultiLDAP) User(login string) (
 
 		defer server.Close()
 
+		if err := server.Bind(); err != nil {
+			return nil, err
+		}
+
 		users, err := server.Users(search)
 		if err != nil {
 			return nil, err
@@ -142,6 +146,10 @@ func (multiples *MultiLDAP) Users(logins []string) (
 
 		defer server.Close()
 
+		if err := server.Bind(); err != nil {
+			return nil, err
+		}
+
 		users, err := server.Users(logins)
 		if err != nil {
 			return nil, err

+ 10 - 2
pkg/services/multildap/testing.go

@@ -11,12 +11,15 @@ type MockLDAP struct {
 	loginCalledTimes int
 	closeCalledTimes int
 	usersCalledTimes int
+	bindCalledTimes  int
 
 	dialErrReturn error
 
 	loginErrReturn error
 	loginReturn    *models.ExternalUserInfo
 
+	bindErrReturn error
+
 	usersErrReturn   error
 	usersFirstReturn []*models.ExternalUserInfo
 	usersRestReturn  []*models.ExternalUserInfo
@@ -40,8 +43,8 @@ func (mock *MockLDAP) Users([]string) ([]*models.ExternalUserInfo, error) {
 	return mock.usersRestReturn, mock.usersErrReturn
 }
 
-// Auth test fn
-func (mock *MockLDAP) Auth(string, string) error {
+// UserBind test fn
+func (mock *MockLDAP) UserBind(string, string) error {
 	return nil
 }
 
@@ -56,6 +59,11 @@ func (mock *MockLDAP) Close() {
 	mock.closeCalledTimes = mock.closeCalledTimes + 1
 }
 
+func (mock *MockLDAP) Bind() error {
+	mock.bindCalledTimes++
+	return mock.bindErrReturn
+}
+
 // MockMultiLDAP represents testing struct for multildap testing
 type MockMultiLDAP struct {
 	LoginCalledTimes int