LDAP: Move to single package cluster (#63035)
* move multildap to ldap package * move LDAP api and tests to ldap package * register background service * lint
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
package multildap
|
||||
|
||||
import (
|
||||
"github.com/grafana/grafana/pkg/services/ldap"
|
||||
"github.com/grafana/grafana/pkg/services/login"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
)
|
||||
|
||||
type MultiLDAPmock struct {
|
||||
MultiLDAP
|
||||
ID int64
|
||||
UserCalled bool
|
||||
LoginCalled bool
|
||||
UserInfo *user.User
|
||||
AuthModule string
|
||||
ExpectedErr error
|
||||
}
|
||||
|
||||
func (m *MultiLDAPmock) Login(query *login.LoginUserQuery) (
|
||||
*login.ExternalUserInfo, error,
|
||||
) {
|
||||
m.LoginCalled = true
|
||||
query.User = m.UserInfo
|
||||
query.AuthModule = m.AuthModule
|
||||
result := &login.ExternalUserInfo{
|
||||
UserId: m.ID,
|
||||
}
|
||||
return result, m.ExpectedErr
|
||||
}
|
||||
|
||||
func (m *MultiLDAPmock) User(loginstr string) (
|
||||
*login.ExternalUserInfo,
|
||||
ldap.ServerConfig,
|
||||
error,
|
||||
) {
|
||||
m.UserCalled = true
|
||||
result := &login.ExternalUserInfo{
|
||||
UserId: m.ID,
|
||||
}
|
||||
return result, ldap.ServerConfig{}, nil
|
||||
}
|
||||
@@ -0,0 +1,262 @@
|
||||
package multildap
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/ldap"
|
||||
"github.com/grafana/grafana/pkg/services/login"
|
||||
)
|
||||
|
||||
// logger to log
|
||||
var logger = log.New("ldap")
|
||||
|
||||
// GetConfig gets LDAP config
|
||||
var GetConfig = ldap.GetConfig
|
||||
|
||||
// IsEnabled checks if LDAP is enabled
|
||||
var IsEnabled = ldap.IsEnabled
|
||||
|
||||
// newLDAP return instance of the single LDAP server
|
||||
var newLDAP = ldap.New
|
||||
|
||||
// ErrInvalidCredentials is returned if username and password do not match
|
||||
var ErrInvalidCredentials = ldap.ErrInvalidCredentials
|
||||
|
||||
// ErrCouldNotFindUser is returned when username hasn't been found (not username+password)
|
||||
var ErrCouldNotFindUser = ldap.ErrCouldNotFindUser
|
||||
|
||||
// ErrNoLDAPServers is returned when there is no LDAP servers specified
|
||||
var ErrNoLDAPServers = errors.New("no LDAP servers are configured")
|
||||
|
||||
// ErrDidNotFindUser if request for user is unsuccessful
|
||||
var ErrDidNotFindUser = errors.New("did not find a user")
|
||||
|
||||
// ServerStatus holds the LDAP server status
|
||||
type ServerStatus struct {
|
||||
Host string
|
||||
Port int
|
||||
Available bool
|
||||
Error error
|
||||
}
|
||||
|
||||
// IMultiLDAP is interface for MultiLDAP
|
||||
type IMultiLDAP interface {
|
||||
Ping() ([]*ServerStatus, error)
|
||||
Login(query *login.LoginUserQuery) (
|
||||
*login.ExternalUserInfo, error,
|
||||
)
|
||||
|
||||
Users(logins []string) (
|
||||
[]*login.ExternalUserInfo, error,
|
||||
)
|
||||
|
||||
User(login string) (
|
||||
*login.ExternalUserInfo, ldap.ServerConfig, error,
|
||||
)
|
||||
}
|
||||
|
||||
// MultiLDAP is basic struct of LDAP authorization
|
||||
type MultiLDAP struct {
|
||||
configs []*ldap.ServerConfig
|
||||
}
|
||||
|
||||
// New creates the new LDAP auth
|
||||
func New(configs []*ldap.ServerConfig) IMultiLDAP {
|
||||
return &MultiLDAP{
|
||||
configs: configs,
|
||||
}
|
||||
}
|
||||
|
||||
// Ping dials each of the LDAP servers and returns their status. If the server is unavailable, it also returns the error.
|
||||
func (multiples *MultiLDAP) Ping() ([]*ServerStatus, error) {
|
||||
if len(multiples.configs) == 0 {
|
||||
return nil, ErrNoLDAPServers
|
||||
}
|
||||
|
||||
serverStatuses := []*ServerStatus{}
|
||||
for _, config := range multiples.configs {
|
||||
status := &ServerStatus{}
|
||||
|
||||
status.Host = config.Host
|
||||
status.Port = config.Port
|
||||
|
||||
server := newLDAP(config)
|
||||
err := server.Dial()
|
||||
|
||||
if err == nil {
|
||||
status.Available = true
|
||||
serverStatuses = append(serverStatuses, status)
|
||||
server.Close()
|
||||
} else {
|
||||
status.Available = false
|
||||
status.Error = err
|
||||
serverStatuses = append(serverStatuses, status)
|
||||
}
|
||||
}
|
||||
|
||||
return serverStatuses, nil
|
||||
}
|
||||
|
||||
// Login tries to log in the user in multiples LDAP
|
||||
func (multiples *MultiLDAP) Login(query *login.LoginUserQuery) (
|
||||
*login.ExternalUserInfo, error,
|
||||
) {
|
||||
if len(multiples.configs) == 0 {
|
||||
return nil, ErrNoLDAPServers
|
||||
}
|
||||
|
||||
ldapSilentErrors := []error{}
|
||||
|
||||
for index, config := range multiples.configs {
|
||||
server := newLDAP(config)
|
||||
|
||||
if err := server.Dial(); err != nil {
|
||||
logDialFailure(err, config)
|
||||
|
||||
// Only return an error if it is the last server so we can try next server
|
||||
if index == len(multiples.configs)-1 {
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
defer server.Close()
|
||||
|
||||
user, err := server.Login(query)
|
||||
if err != nil {
|
||||
if isSilentError(err) {
|
||||
ldapSilentErrors = append(ldapSilentErrors, err)
|
||||
logger.Debug(
|
||||
"unable to login with LDAP - skipping server",
|
||||
"host", config.Host,
|
||||
"port", config.Port,
|
||||
"error", err,
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if user != nil {
|
||||
return user, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Return ErrInvalidCredentials in case any of the errors was ErrInvalidCredentials (means that the authentication has failed at least once)
|
||||
for _, ldapErr := range ldapSilentErrors {
|
||||
if errors.Is(ldapErr, ErrInvalidCredentials) {
|
||||
return nil, ErrInvalidCredentials
|
||||
}
|
||||
}
|
||||
|
||||
// Return ErrCouldNotFindUser if all of the configured LDAP servers returned with ErrCouldNotFindUser
|
||||
return nil, ErrCouldNotFindUser
|
||||
}
|
||||
|
||||
// User attempts to find an user by login/username by searching into all of the configured LDAP servers. Then, if the user is found it returns the user alongisde the server it was found.
|
||||
func (multiples *MultiLDAP) User(login string) (
|
||||
*login.ExternalUserInfo,
|
||||
ldap.ServerConfig,
|
||||
error,
|
||||
) {
|
||||
if len(multiples.configs) == 0 {
|
||||
return nil, ldap.ServerConfig{}, ErrNoLDAPServers
|
||||
}
|
||||
|
||||
search := []string{login}
|
||||
for index, config := range multiples.configs {
|
||||
server := newLDAP(config)
|
||||
|
||||
if err := server.Dial(); err != nil {
|
||||
logDialFailure(err, config)
|
||||
|
||||
// Only return an error if it is the last server so we can try next server
|
||||
if index == len(multiples.configs)-1 {
|
||||
return nil, *config, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
defer server.Close()
|
||||
|
||||
if err := server.Bind(); err != nil {
|
||||
return nil, *config, err
|
||||
}
|
||||
|
||||
users, err := server.Users(search)
|
||||
if err != nil {
|
||||
return nil, *config, err
|
||||
}
|
||||
|
||||
if len(users) != 0 {
|
||||
return users[0], *config, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, ldap.ServerConfig{}, ErrDidNotFindUser
|
||||
}
|
||||
|
||||
// Users gets users from multiple LDAP servers
|
||||
func (multiples *MultiLDAP) Users(logins []string) (
|
||||
[]*login.ExternalUserInfo,
|
||||
error,
|
||||
) {
|
||||
var result []*login.ExternalUserInfo
|
||||
|
||||
if len(multiples.configs) == 0 {
|
||||
return nil, ErrNoLDAPServers
|
||||
}
|
||||
|
||||
for index, config := range multiples.configs {
|
||||
server := newLDAP(config)
|
||||
|
||||
if err := server.Dial(); err != nil {
|
||||
logDialFailure(err, config)
|
||||
|
||||
// Only return an error if it is the last server so we can try next server
|
||||
if index == len(multiples.configs)-1 {
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
defer server.Close()
|
||||
|
||||
if err := server.Bind(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
users, err := server.Users(logins)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, users...)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// isSilentError evaluates an error and tells whenever we should fail the LDAP request
|
||||
// immediately or if we should continue into other LDAP servers
|
||||
func isSilentError(err error) bool {
|
||||
continueErrs := []error{ErrInvalidCredentials, ErrCouldNotFindUser}
|
||||
|
||||
for _, cerr := range continueErrs {
|
||||
if errors.Is(err, cerr) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func logDialFailure(err error, config *ldap.ServerConfig) {
|
||||
logger.Debug(
|
||||
"unable to dial LDAP server",
|
||||
"host", config.Host,
|
||||
"port", config.Port,
|
||||
"error", err,
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,523 @@
|
||||
package multildap
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/ldap"
|
||||
"github.com/grafana/grafana/pkg/services/login"
|
||||
|
||||
//TODO(sh0rez): remove once import cycle resolved
|
||||
_ "github.com/grafana/grafana/pkg/api/response"
|
||||
)
|
||||
|
||||
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(&login.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(&login.LoginUserQuery{})
|
||||
|
||||
require.Error(t, err)
|
||||
require.Equal(t, expected, err)
|
||||
|
||||
teardown()
|
||||
})
|
||||
|
||||
t.Run("Should call underlying LDAP methods", func(t *testing.T) {
|
||||
mock := setup()
|
||||
mock.loginErrReturn = ErrInvalidCredentials
|
||||
|
||||
multi := New([]*ldap.ServerConfig{
|
||||
{}, {},
|
||||
})
|
||||
_, err := multi.Login(&login.LoginUserQuery{})
|
||||
|
||||
require.Equal(t, 2, mock.dialCalledTimes)
|
||||
require.Equal(t, 2, mock.loginCalledTimes)
|
||||
require.Equal(t, 2, mock.closeCalledTimes)
|
||||
|
||||
require.Equal(t, ldap.ErrInvalidCredentials, err)
|
||||
|
||||
teardown()
|
||||
})
|
||||
|
||||
t.Run("Should get login result", func(t *testing.T) {
|
||||
mock := setup()
|
||||
|
||||
mock.loginReturn = &login.ExternalUserInfo{
|
||||
Login: "killa",
|
||||
}
|
||||
|
||||
multi := New([]*ldap.ServerConfig{
|
||||
{}, {},
|
||||
})
|
||||
result, err := multi.Login(&login.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(&login.LoginUserQuery{})
|
||||
|
||||
require.Equal(t, 2, mock.dialCalledTimes)
|
||||
require.Equal(t, 2, mock.loginCalledTimes)
|
||||
require.Equal(t, 2, mock.closeCalledTimes)
|
||||
|
||||
require.Equal(t, ErrCouldNotFindUser, 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(&login.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(&login.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(&login.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 = []*login.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 = []*login.ExternalUserInfo{
|
||||
{
|
||||
Login: "one",
|
||||
},
|
||||
|
||||
{
|
||||
Login: "two",
|
||||
},
|
||||
}
|
||||
|
||||
mock.usersRestReturn = []*login.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 *login.ExternalUserInfo
|
||||
|
||||
bindErrReturn error
|
||||
|
||||
usersErrReturn error
|
||||
usersFirstReturn []*login.ExternalUserInfo
|
||||
usersRestReturn []*login.ExternalUserInfo
|
||||
}
|
||||
|
||||
// Login test fn
|
||||
func (mock *mockLDAP) Login(*login.LoginUserQuery) (*login.ExternalUserInfo, error) {
|
||||
mock.loginCalledTimes++
|
||||
return mock.loginReturn, mock.loginErrReturn
|
||||
}
|
||||
|
||||
// Users test fn
|
||||
func (mock *mockLDAP) Users([]string) ([]*login.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
|
||||
}
|
||||
Reference in New Issue
Block a user