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 { ...@@ -31,7 +31,8 @@ type IConnection interface {
type IServer interface { type IServer interface {
Login(*models.LoginUserQuery) (*models.ExternalUserInfo, error) Login(*models.LoginUserQuery) (*models.ExternalUserInfo, error)
Users([]string) ([]*models.ExternalUserInfo, error) Users([]string) ([]*models.ExternalUserInfo, error)
Auth(string, string) error Bind() error
UserBind(string, string) error
Dial() error Dial() error
Close() Close()
} }
...@@ -43,6 +44,23 @@ type Server struct { ...@@ -43,6 +44,23 @@ type Server struct {
log log.Logger 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(). // UsersMaxRequest is a max amount of users we can request via Users().
// Since many LDAP servers has limitations // Since many LDAP servers has limitations
// on how much items can we return in one request // on how much items can we return in one request
...@@ -149,7 +167,7 @@ func (server *Server) Login(query *models.LoginUserQuery) ( ...@@ -149,7 +167,7 @@ func (server *Server) Login(query *models.LoginUserQuery) (
} }
} else if server.shouldSingleBind() { } else if server.shouldSingleBind() {
authAndBind = true authAndBind = true
err = server.Auth(server.singleBindDN(query.Username), query.Password) err = server.UserBind(server.singleBindDN(query.Username), query.Password)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -179,7 +197,7 @@ func (server *Server) Login(query *models.LoginUserQuery) ( ...@@ -179,7 +197,7 @@ func (server *Server) Login(query *models.LoginUserQuery) (
if !authAndBind { if !authAndBind {
// Authenticate user // Authenticate user
err = server.Auth(user.AuthId, query.Password) err = server.UserBind(user.AuthId, query.Password)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -380,9 +398,9 @@ func (server *Server) shouldAuthAdmin() bool { ...@@ -380,9 +398,9 @@ func (server *Server) shouldAuthAdmin() bool {
return server.Config.BindPassword != "" return server.Config.BindPassword != ""
} }
// Auth authentificates user in LDAP // UserBind authenticates the connection with the LDAP server
func (server *Server) Auth(username, password string) error { func (server *Server) UserBind(username, password string) error {
err := server.auth(username, password) err := server.userBind(username, password)
if err != nil { if err != nil {
server.log.Error( server.log.Error(
fmt.Sprintf("Cannot authentificate user %s in LDAP", username), fmt.Sprintf("Cannot authentificate user %s in LDAP", username),
...@@ -397,7 +415,7 @@ func (server *Server) Auth(username, password string) error { ...@@ -397,7 +415,7 @@ func (server *Server) Auth(username, password string) error {
// AuthAdmin authentificates LDAP admin user // AuthAdmin authentificates LDAP admin user
func (server *Server) AuthAdmin() error { 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 { if err != nil {
server.log.Error( server.log.Error(
"Cannot authentificate admin user in LDAP", "Cannot authentificate admin user in LDAP",
...@@ -410,8 +428,8 @@ func (server *Server) AuthAdmin() error { ...@@ -410,8 +428,8 @@ func (server *Server) AuthAdmin() error {
return nil return nil
} }
// auth is helper for several types of LDAP authentification // userBind authenticates the connection with the LDAP server
func (server *Server) auth(path, password string) error { func (server *Server) userBind(path, password string) error {
err := server.Connection.Bind(path, password) err := server.Connection.Bind(path, password)
if err != nil { if err != nil {
if ldapErr, ok := err.(*ldap.Error); ok { if ldapErr, ok := err.(*ldap.Error); ok {
......
...@@ -19,7 +19,7 @@ func TestLDAPLogin(t *testing.T) { ...@@ -19,7 +19,7 @@ func TestLDAPLogin(t *testing.T) {
} }
Convey("Login()", t, func() { Convey("Login()", t, func() {
Convey("Should get invalid credentials when auth fails", func() { Convey("Should get invalid credentials when userBind fails", func() {
connection := &MockConnection{} connection := &MockConnection{}
entry := ldap.Entry{} entry := ldap.Entry{}
result := ldap.SearchResult{Entries: []*ldap.Entry{&entry}} result := ldap.SearchResult{Entries: []*ldap.Entry{&entry}}
......
...@@ -145,7 +145,7 @@ func TestLDAPPrivateMethods(t *testing.T) { ...@@ -145,7 +145,7 @@ func TestLDAPPrivateMethods(t *testing.T) {
}) })
Convey("shouldAuthAdmin()", t, func() { Convey("shouldAuthAdmin()", t, func() {
Convey("it should require admin auth", func() { Convey("it should require admin userBind", func() {
server := &Server{ server := &Server{
Config: &ServerConfig{ Config: &ServerConfig{
BindPassword: "test", BindPassword: "test",
...@@ -156,7 +156,7 @@ func TestLDAPPrivateMethods(t *testing.T) { ...@@ -156,7 +156,7 @@ func TestLDAPPrivateMethods(t *testing.T) {
So(result, ShouldBeTrue) So(result, ShouldBeTrue)
}) })
Convey("it should not require admin auth", func() { Convey("it should not require admin userBind", func() {
server := &Server{ server := &Server{
Config: &ServerConfig{ Config: &ServerConfig{
BindPassword: "", BindPassword: "",
......
...@@ -102,7 +102,7 @@ func TestPublicAPI(t *testing.T) { ...@@ -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() { Convey("Should use provided DN and password", func() {
connection := &MockConnection{} connection := &MockConnection{}
var actualUsername, actualPassword string var actualUsername, actualPassword string
...@@ -119,7 +119,7 @@ func TestPublicAPI(t *testing.T) { ...@@ -119,7 +119,7 @@ func TestPublicAPI(t *testing.T) {
} }
dn := "cn=user,ou=users,dc=grafana,dc=org" dn := "cn=user,ou=users,dc=grafana,dc=org"
err := server.Auth(dn, "pwd") err := server.UserBind(dn, "pwd")
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(actualUsername, ShouldEqual, dn) So(actualUsername, ShouldEqual, dn)
...@@ -141,7 +141,7 @@ func TestPublicAPI(t *testing.T) { ...@@ -141,7 +141,7 @@ func TestPublicAPI(t *testing.T) {
}, },
log: log.New("test-logger"), log: log.New("test-logger"),
} }
err := server.Auth("user", "pwd") err := server.UserBind("user", "pwd")
So(err, ShouldEqual, expected) So(err, ShouldEqual, expected)
}) })
}) })
......
...@@ -109,6 +109,10 @@ func (multiples *MultiLDAP) User(login string) ( ...@@ -109,6 +109,10 @@ func (multiples *MultiLDAP) User(login string) (
defer server.Close() defer server.Close()
if err := server.Bind(); err != nil {
return nil, err
}
users, err := server.Users(search) users, err := server.Users(search)
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -142,6 +146,10 @@ func (multiples *MultiLDAP) Users(logins []string) ( ...@@ -142,6 +146,10 @@ func (multiples *MultiLDAP) Users(logins []string) (
defer server.Close() defer server.Close()
if err := server.Bind(); err != nil {
return nil, err
}
users, err := server.Users(logins) users, err := server.Users(logins)
if err != nil { if err != nil {
return nil, err return nil, err
......
...@@ -11,12 +11,15 @@ type MockLDAP struct { ...@@ -11,12 +11,15 @@ type MockLDAP struct {
loginCalledTimes int loginCalledTimes int
closeCalledTimes int closeCalledTimes int
usersCalledTimes int usersCalledTimes int
bindCalledTimes int
dialErrReturn error dialErrReturn error
loginErrReturn error loginErrReturn error
loginReturn *models.ExternalUserInfo loginReturn *models.ExternalUserInfo
bindErrReturn error
usersErrReturn error usersErrReturn error
usersFirstReturn []*models.ExternalUserInfo usersFirstReturn []*models.ExternalUserInfo
usersRestReturn []*models.ExternalUserInfo usersRestReturn []*models.ExternalUserInfo
...@@ -40,8 +43,8 @@ func (mock *MockLDAP) Users([]string) ([]*models.ExternalUserInfo, error) { ...@@ -40,8 +43,8 @@ func (mock *MockLDAP) Users([]string) ([]*models.ExternalUserInfo, error) {
return mock.usersRestReturn, mock.usersErrReturn return mock.usersRestReturn, mock.usersErrReturn
} }
// Auth test fn // UserBind test fn
func (mock *MockLDAP) Auth(string, string) error { func (mock *MockLDAP) UserBind(string, string) error {
return nil return nil
} }
...@@ -56,6 +59,11 @@ func (mock *MockLDAP) Close() { ...@@ -56,6 +59,11 @@ func (mock *MockLDAP) Close() {
mock.closeCalledTimes = mock.closeCalledTimes + 1 mock.closeCalledTimes = mock.closeCalledTimes + 1
} }
func (mock *MockLDAP) Bind() error {
mock.bindCalledTimes++
return mock.bindErrReturn
}
// MockMultiLDAP represents testing struct for multildap testing // MockMultiLDAP represents testing struct for multildap testing
type MockMultiLDAP struct { type MockMultiLDAP struct {
LoginCalledTimes int 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