Commit 5d3a60d4 by Leonard Gram Committed by GitHub

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

parent 5f0a7f43
......@@ -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 {
......
......@@ -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}}
......
......@@ -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: "",
......
......@@ -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)
})
})
......
......@@ -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
......
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment