mirror of
https://github.com/grafana/grafana.git
synced 2024-11-30 20:54:22 -06:00
520 lines
11 KiB
Go
520 lines
11 KiB
Go
package multildap
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
|
|
"github.com/grafana/grafana/pkg/models"
|
|
"github.com/grafana/grafana/pkg/services/ldap"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestMultiLDAP(t *testing.T) {
|
|
t.Run("Ping()", func(t *testing.T) {
|
|
t.Run("Should return error for absent config list", func(t *testing.T) {
|
|
setup()
|
|
|
|
multi := New([]*ldap.ServerConfig{})
|
|
_, err := multi.Ping()
|
|
|
|
require.Error(t, err)
|
|
require.Equal(t, ErrNoLDAPServers, err)
|
|
|
|
teardown()
|
|
})
|
|
t.Run("Should return an unavailable status on dial error", func(t *testing.T) {
|
|
mock := setup()
|
|
|
|
expectedErr := errors.New("Dial error")
|
|
mock.dialErrReturn = expectedErr
|
|
|
|
multi := New([]*ldap.ServerConfig{
|
|
{Host: "10.0.0.1", Port: 361},
|
|
})
|
|
|
|
statuses, err := multi.Ping()
|
|
|
|
require.Nil(t, err)
|
|
require.Equal(t, "10.0.0.1", statuses[0].Host)
|
|
require.Equal(t, 361, statuses[0].Port)
|
|
require.False(t, statuses[0].Available)
|
|
require.Equal(t, expectedErr, statuses[0].Error)
|
|
require.Equal(t, 0, mock.closeCalledTimes)
|
|
|
|
teardown()
|
|
})
|
|
t.Run("Should get the LDAP server statuses", func(t *testing.T) {
|
|
mock := setup()
|
|
|
|
multi := New([]*ldap.ServerConfig{
|
|
{Host: "10.0.0.1", Port: 361},
|
|
})
|
|
|
|
statuses, err := multi.Ping()
|
|
|
|
require.Nil(t, err)
|
|
require.Equal(t, "10.0.0.1", statuses[0].Host)
|
|
require.Equal(t, 361, statuses[0].Port)
|
|
require.True(t, statuses[0].Available)
|
|
require.Nil(t, statuses[0].Error)
|
|
require.Equal(t, 1, mock.closeCalledTimes)
|
|
|
|
teardown()
|
|
})
|
|
})
|
|
t.Run("Login()", func(t *testing.T) {
|
|
t.Run("Should return error for absent config list", func(t *testing.T) {
|
|
setup()
|
|
|
|
multi := New([]*ldap.ServerConfig{})
|
|
_, err := multi.Login(&models.LoginUserQuery{})
|
|
|
|
require.Error(t, err)
|
|
require.Equal(t, ErrNoLDAPServers, err)
|
|
|
|
teardown()
|
|
})
|
|
|
|
t.Run("Should return a dial error", func(t *testing.T) {
|
|
mock := setup()
|
|
|
|
expected := errors.New("Dial error")
|
|
mock.dialErrReturn = expected
|
|
|
|
multi := New([]*ldap.ServerConfig{
|
|
{}, {},
|
|
})
|
|
|
|
_, err := multi.Login(&models.LoginUserQuery{})
|
|
|
|
require.Error(t, err)
|
|
require.Equal(t, expected, err)
|
|
|
|
teardown()
|
|
})
|
|
|
|
t.Run("Should call underlying LDAP methods", func(t *testing.T) {
|
|
mock := setup()
|
|
|
|
multi := New([]*ldap.ServerConfig{
|
|
{}, {},
|
|
})
|
|
_, err := multi.Login(&models.LoginUserQuery{})
|
|
|
|
require.Equal(t, 2, mock.dialCalledTimes)
|
|
require.Equal(t, 2, mock.loginCalledTimes)
|
|
require.Equal(t, 2, mock.closeCalledTimes)
|
|
|
|
require.Equal(t, ErrInvalidCredentials, err)
|
|
|
|
teardown()
|
|
})
|
|
|
|
t.Run("Should get login result", func(t *testing.T) {
|
|
mock := setup()
|
|
|
|
mock.loginReturn = &models.ExternalUserInfo{
|
|
Login: "killa",
|
|
}
|
|
|
|
multi := New([]*ldap.ServerConfig{
|
|
{}, {},
|
|
})
|
|
result, err := multi.Login(&models.LoginUserQuery{})
|
|
|
|
require.Equal(t, 1, mock.dialCalledTimes)
|
|
require.Equal(t, 1, mock.loginCalledTimes)
|
|
require.Equal(t, 1, mock.closeCalledTimes)
|
|
|
|
require.Equal(t, "killa", result.Login)
|
|
require.Nil(t, err)
|
|
|
|
teardown()
|
|
})
|
|
|
|
t.Run("Should still call a second error for invalid not found error", func(t *testing.T) {
|
|
mock := setup()
|
|
|
|
mock.loginErrReturn = ErrCouldNotFindUser
|
|
|
|
multi := New([]*ldap.ServerConfig{
|
|
{}, {},
|
|
})
|
|
_, err := multi.Login(&models.LoginUserQuery{})
|
|
|
|
require.Equal(t, 2, mock.dialCalledTimes)
|
|
require.Equal(t, 2, mock.loginCalledTimes)
|
|
require.Equal(t, 2, mock.closeCalledTimes)
|
|
|
|
require.Equal(t, ErrInvalidCredentials, err)
|
|
|
|
teardown()
|
|
})
|
|
|
|
t.Run("Should still try to auth with the second server after receiving an invalid credentials error from the first", func(t *testing.T) {
|
|
mock := setup()
|
|
|
|
mock.loginErrReturn = ErrInvalidCredentials
|
|
|
|
multi := New([]*ldap.ServerConfig{
|
|
{}, {},
|
|
})
|
|
_, err := multi.Login(&models.LoginUserQuery{})
|
|
|
|
require.Equal(t, 2, mock.dialCalledTimes)
|
|
require.Equal(t, 2, mock.loginCalledTimes)
|
|
require.Equal(t, 2, mock.closeCalledTimes)
|
|
|
|
require.Equal(t, ErrInvalidCredentials, err)
|
|
|
|
teardown()
|
|
})
|
|
|
|
t.Run("Should still try to auth with the second server after receiving a dial error from the first", func(t *testing.T) {
|
|
mock := setup()
|
|
|
|
expectedError := errors.New("Dial error")
|
|
mock.dialErrReturn = expectedError
|
|
|
|
multi := New([]*ldap.ServerConfig{
|
|
{}, {},
|
|
})
|
|
_, err := multi.Login(&models.LoginUserQuery{})
|
|
|
|
require.Equal(t, 2, mock.dialCalledTimes)
|
|
|
|
require.Equal(t, expectedError, err)
|
|
|
|
teardown()
|
|
})
|
|
|
|
t.Run("Should return unknown error", func(t *testing.T) {
|
|
mock := setup()
|
|
|
|
expected := errors.New("Something unknown")
|
|
mock.loginErrReturn = expected
|
|
|
|
multi := New([]*ldap.ServerConfig{
|
|
{}, {},
|
|
})
|
|
_, err := multi.Login(&models.LoginUserQuery{})
|
|
|
|
require.Equal(t, 1, mock.dialCalledTimes)
|
|
require.Equal(t, 1, mock.loginCalledTimes)
|
|
require.Equal(t, 1, mock.closeCalledTimes)
|
|
|
|
require.Equal(t, expected, err)
|
|
|
|
teardown()
|
|
})
|
|
})
|
|
|
|
t.Run("User()", func(t *testing.T) {
|
|
t.Run("Should return error for absent config list", func(t *testing.T) {
|
|
setup()
|
|
|
|
multi := New([]*ldap.ServerConfig{})
|
|
_, _, err := multi.User("test")
|
|
|
|
require.Error(t, err)
|
|
require.Equal(t, ErrNoLDAPServers, err)
|
|
|
|
teardown()
|
|
})
|
|
|
|
t.Run("Should return a dial error", func(t *testing.T) {
|
|
mock := setup()
|
|
|
|
expected := errors.New("Dial error")
|
|
mock.dialErrReturn = expected
|
|
|
|
multi := New([]*ldap.ServerConfig{
|
|
{}, {},
|
|
})
|
|
|
|
_, _, err := multi.User("test")
|
|
|
|
require.Error(t, err)
|
|
require.Equal(t, expected, err)
|
|
|
|
teardown()
|
|
})
|
|
|
|
t.Run("Should call underlying LDAP methods", func(t *testing.T) {
|
|
mock := setup()
|
|
|
|
multi := New([]*ldap.ServerConfig{
|
|
{}, {},
|
|
})
|
|
_, _, err := multi.User("test")
|
|
|
|
require.Equal(t, 2, mock.dialCalledTimes)
|
|
require.Equal(t, 2, mock.usersCalledTimes)
|
|
require.Equal(t, 2, mock.closeCalledTimes)
|
|
|
|
require.Equal(t, ErrDidNotFindUser, err)
|
|
|
|
teardown()
|
|
})
|
|
|
|
t.Run("Should return some error", func(t *testing.T) {
|
|
mock := setup()
|
|
|
|
expected := errors.New("Killa Gorilla")
|
|
mock.usersErrReturn = expected
|
|
|
|
multi := New([]*ldap.ServerConfig{
|
|
{}, {},
|
|
})
|
|
_, _, err := multi.User("test")
|
|
|
|
require.Equal(t, 1, mock.dialCalledTimes)
|
|
require.Equal(t, 1, mock.usersCalledTimes)
|
|
require.Equal(t, 1, mock.closeCalledTimes)
|
|
|
|
require.Equal(t, expected, err)
|
|
|
|
teardown()
|
|
})
|
|
|
|
t.Run("Should get only one user", func(t *testing.T) {
|
|
mock := setup()
|
|
|
|
mock.usersFirstReturn = []*models.ExternalUserInfo{
|
|
{
|
|
Login: "one",
|
|
},
|
|
|
|
{
|
|
Login: "two",
|
|
},
|
|
}
|
|
|
|
multi := New([]*ldap.ServerConfig{
|
|
{}, {},
|
|
})
|
|
user, _, err := multi.User("test")
|
|
|
|
require.Equal(t, 1, mock.dialCalledTimes)
|
|
require.Equal(t, 1, mock.usersCalledTimes)
|
|
require.Equal(t, 1, mock.closeCalledTimes)
|
|
|
|
require.Nil(t, err)
|
|
require.Equal(t, "one", user.Login)
|
|
|
|
teardown()
|
|
})
|
|
|
|
t.Run("Should still try to auth with the second server after receiving a dial error from the first", func(t *testing.T) {
|
|
mock := setup()
|
|
|
|
expectedError := errors.New("Dial error")
|
|
mock.dialErrReturn = expectedError
|
|
|
|
multi := New([]*ldap.ServerConfig{
|
|
{}, {},
|
|
})
|
|
_, _, err := multi.User("test")
|
|
|
|
require.Equal(t, 2, mock.dialCalledTimes)
|
|
require.Equal(t, expectedError, err)
|
|
|
|
teardown()
|
|
})
|
|
})
|
|
|
|
t.Run("Users()", func(t *testing.T) {
|
|
t.Run("Should still try to auth with the second server after receiving a dial error from the first", func(t *testing.T) {
|
|
mock := setup()
|
|
|
|
expectedError := errors.New("Dial error")
|
|
mock.dialErrReturn = expectedError
|
|
|
|
multi := New([]*ldap.ServerConfig{
|
|
{}, {},
|
|
})
|
|
_, err := multi.Users([]string{"test"})
|
|
|
|
require.Equal(t, 2, mock.dialCalledTimes)
|
|
require.Equal(t, expectedError, err)
|
|
|
|
teardown()
|
|
})
|
|
t.Run("Should return error for absent config list", func(t *testing.T) {
|
|
setup()
|
|
|
|
multi := New([]*ldap.ServerConfig{})
|
|
_, err := multi.Users([]string{"test"})
|
|
|
|
require.Error(t, err)
|
|
require.Equal(t, ErrNoLDAPServers, err)
|
|
|
|
teardown()
|
|
})
|
|
|
|
t.Run("Should return a dial error", func(t *testing.T) {
|
|
mock := setup()
|
|
|
|
expected := errors.New("Dial error")
|
|
mock.dialErrReturn = expected
|
|
|
|
multi := New([]*ldap.ServerConfig{
|
|
{}, {},
|
|
})
|
|
|
|
_, err := multi.Users([]string{"test"})
|
|
|
|
require.Error(t, err)
|
|
require.Equal(t, expected, err)
|
|
|
|
teardown()
|
|
})
|
|
|
|
t.Run("Should call underlying LDAP methods", func(t *testing.T) {
|
|
mock := setup()
|
|
|
|
multi := New([]*ldap.ServerConfig{
|
|
{}, {},
|
|
})
|
|
_, err := multi.Users([]string{"test"})
|
|
|
|
require.Equal(t, 2, mock.dialCalledTimes)
|
|
require.Equal(t, 2, mock.usersCalledTimes)
|
|
require.Equal(t, 2, mock.closeCalledTimes)
|
|
|
|
require.Nil(t, err)
|
|
|
|
teardown()
|
|
})
|
|
|
|
t.Run("Should return some error", func(t *testing.T) {
|
|
mock := setup()
|
|
|
|
expected := errors.New("Killa Gorilla")
|
|
mock.usersErrReturn = expected
|
|
|
|
multi := New([]*ldap.ServerConfig{
|
|
{}, {},
|
|
})
|
|
_, err := multi.Users([]string{"test"})
|
|
|
|
require.Equal(t, 1, mock.dialCalledTimes)
|
|
require.Equal(t, 1, mock.usersCalledTimes)
|
|
require.Equal(t, 1, mock.closeCalledTimes)
|
|
|
|
require.Equal(t, expected, err)
|
|
|
|
teardown()
|
|
})
|
|
|
|
t.Run("Should get users", func(t *testing.T) {
|
|
mock := setup()
|
|
|
|
mock.usersFirstReturn = []*models.ExternalUserInfo{
|
|
{
|
|
Login: "one",
|
|
},
|
|
|
|
{
|
|
Login: "two",
|
|
},
|
|
}
|
|
|
|
mock.usersRestReturn = []*models.ExternalUserInfo{
|
|
{
|
|
Login: "three",
|
|
},
|
|
}
|
|
|
|
multi := New([]*ldap.ServerConfig{
|
|
{}, {},
|
|
})
|
|
users, err := multi.Users([]string{"test"})
|
|
|
|
require.Equal(t, 2, mock.dialCalledTimes)
|
|
require.Equal(t, 2, mock.usersCalledTimes)
|
|
require.Equal(t, 2, mock.closeCalledTimes)
|
|
|
|
require.Nil(t, err)
|
|
require.Equal(t, "one", users[0].Login)
|
|
require.Equal(t, "two", users[1].Login)
|
|
require.Equal(t, "three", users[2].Login)
|
|
|
|
teardown()
|
|
})
|
|
})
|
|
}
|
|
|
|
// mockLDAP represents testing struct for ldap testing
|
|
type mockLDAP struct {
|
|
dialCalledTimes int
|
|
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
|
|
}
|
|
|
|
// Login test fn
|
|
func (mock *mockLDAP) Login(*models.LoginUserQuery) (*models.ExternalUserInfo, error) {
|
|
mock.loginCalledTimes++
|
|
return mock.loginReturn, mock.loginErrReturn
|
|
}
|
|
|
|
// Users test fn
|
|
func (mock *mockLDAP) Users([]string) ([]*models.ExternalUserInfo, error) {
|
|
mock.usersCalledTimes++
|
|
|
|
if mock.usersCalledTimes == 1 {
|
|
return mock.usersFirstReturn, mock.usersErrReturn
|
|
}
|
|
|
|
return mock.usersRestReturn, mock.usersErrReturn
|
|
}
|
|
|
|
// UserBind test fn
|
|
func (mock *mockLDAP) UserBind(string, string) error {
|
|
return nil
|
|
}
|
|
|
|
// Dial test fn
|
|
func (mock *mockLDAP) Dial() error {
|
|
mock.dialCalledTimes++
|
|
return mock.dialErrReturn
|
|
}
|
|
|
|
// Close test fn
|
|
func (mock *mockLDAP) Close() {
|
|
mock.closeCalledTimes++
|
|
}
|
|
|
|
func (mock *mockLDAP) Bind() error {
|
|
mock.bindCalledTimes++
|
|
return mock.bindErrReturn
|
|
}
|
|
|
|
func setup() *mockLDAP {
|
|
mock := &mockLDAP{}
|
|
|
|
newLDAP = func(config *ldap.ServerConfig) ldap.IServer {
|
|
return mock
|
|
}
|
|
|
|
return mock
|
|
}
|
|
|
|
func teardown() {
|
|
newLDAP = ldap.New
|
|
}
|