LDAP: Move LDAP globals to Config (#63255)

* structure dtos and private methods

* add basic LDAP service

* use LDAP service in ldap debug API

* lower non fatal error

* remove unused globals

* wip

* remove final globals

* fix tests to use cfg enabled

* restructure errors

* remove logger from globals

* use ldap service in authn

* use ldap service in context handler

* fix failed tests

* fix ldap middleware provides

* fix provides in auth_test.go
This commit is contained in:
Jo
2023-02-10 19:01:55 +01:00
committed by GitHub
parent 8520a8614c
commit d4cfbd9fd3
30 changed files with 664 additions and 506 deletions
+54
View File
@@ -0,0 +1,54 @@
package api
import (
"github.com/grafana/grafana/pkg/services/ldap"
"github.com/grafana/grafana/pkg/services/org"
)
// swagger:parameters getUserFromLDAP
type GetLDAPUserParams struct {
// in:path
// required:true
UserName string `json:"user_name"`
}
// swagger:parameters postSyncUserWithLDAP
type SyncLDAPUserParams struct {
// in:path
// required:true
UserID int64 `json:"user_id"`
}
// LDAPAttribute is a serializer for user attributes mapped from LDAP. Is meant to display both the serialized value and the LDAP key we received it from.
type LDAPAttribute struct {
ConfigAttributeValue string `json:"cfgAttrValue"`
LDAPAttributeValue string `json:"ldapValue"`
}
// RoleDTO is a serializer for mapped roles from LDAP
type LDAPRoleDTO struct {
OrgId int64 `json:"orgId"`
OrgName string `json:"orgName"`
OrgRole org.RoleType `json:"orgRole"`
GroupDN string `json:"groupDN"`
}
// LDAPUserDTO is a serializer for users mapped from LDAP
type LDAPUserDTO struct {
Name *LDAPAttribute `json:"name"`
Surname *LDAPAttribute `json:"surname"`
Email *LDAPAttribute `json:"email"`
Username *LDAPAttribute `json:"login"`
IsGrafanaAdmin *bool `json:"isGrafanaAdmin"`
IsDisabled bool `json:"isDisabled"`
OrgRoles []LDAPRoleDTO `json:"roles"`
Teams []ldap.TeamOrgGroupDTO `json:"teams"`
}
// LDAPServerDTO is a serializer for LDAP server statuses
type LDAPServerDTO struct {
Host string `json:"host"`
Port int `json:"port"`
Available bool `json:"available"`
Error string `json:"error"`
}
+11
View File
@@ -0,0 +1,11 @@
package api
import "fmt"
type OrganizationNotFoundError struct {
OrgID int64
}
func (e *OrganizationNotFoundError) Error() string {
return fmt.Sprintf("unable to find organization with ID '%d'", e.OrgID)
}
+53 -120
View File
@@ -17,6 +17,7 @@ import (
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
"github.com/grafana/grafana/pkg/services/ldap"
"github.com/grafana/grafana/pkg/services/ldap/multildap"
"github.com/grafana/grafana/pkg/services/ldap/service"
"github.com/grafana/grafana/pkg/services/login"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/supportbundles"
@@ -26,15 +27,6 @@ import (
"github.com/grafana/grafana/pkg/web"
)
var (
getLDAPConfig = multildap.GetConfig
newLDAP = multildap.New
errOrganizationNotFound = func(orgId int64) error {
return fmt.Errorf("unable to find organization with ID '%d'", orgId)
}
)
type Service struct {
cfg *setting.Cfg
userService user.Service
@@ -44,11 +36,12 @@ type Service struct {
orgService org.Service
sessionService auth.UserTokenService
log log.Logger
ldapService service.LDAP
}
func ProvideService(cfg *setting.Cfg, router routing.RouteRegister, accessControl ac.AccessControl,
userService user.Service, authInfoService login.AuthInfoService, ldapGroupsService ldap.Groups,
loginService login.Service, orgService org.Service,
loginService login.Service, orgService org.Service, ldapService service.LDAP,
sessionService auth.UserTokenService, bundleRegistry supportbundles.Service) *Service {
s := &Service{
cfg: cfg,
@@ -58,6 +51,7 @@ func ProvideService(cfg *setting.Cfg, router routing.RouteRegister, accessContro
loginService: loginService,
orgService: orgService,
sessionService: sessionService,
ldapService: ldapService,
log: log.New("ldap.api"),
}
@@ -85,78 +79,6 @@ func ProvideService(cfg *setting.Cfg, router routing.RouteRegister, accessContro
return s
}
// LDAPAttribute is a serializer for user attributes mapped from LDAP. Is meant to display both the serialized value and the LDAP key we received it from.
type LDAPAttribute struct {
ConfigAttributeValue string `json:"cfgAttrValue"`
LDAPAttributeValue string `json:"ldapValue"`
}
// RoleDTO is a serializer for mapped roles from LDAP
type LDAPRoleDTO struct {
OrgId int64 `json:"orgId"`
OrgName string `json:"orgName"`
OrgRole org.RoleType `json:"orgRole"`
GroupDN string `json:"groupDN"`
}
// LDAPUserDTO is a serializer for users mapped from LDAP
type LDAPUserDTO struct {
Name *LDAPAttribute `json:"name"`
Surname *LDAPAttribute `json:"surname"`
Email *LDAPAttribute `json:"email"`
Username *LDAPAttribute `json:"login"`
IsGrafanaAdmin *bool `json:"isGrafanaAdmin"`
IsDisabled bool `json:"isDisabled"`
OrgRoles []LDAPRoleDTO `json:"roles"`
Teams []ldap.TeamOrgGroupDTO `json:"teams"`
}
// LDAPServerDTO is a serializer for LDAP server statuses
type LDAPServerDTO struct {
Host string `json:"host"`
Port int `json:"port"`
Available bool `json:"available"`
Error string `json:"error"`
}
// FetchOrgs fetches the organization(s) information by executing a single query to the database. Then, populating the DTO with the information retrieved.
func (user *LDAPUserDTO) FetchOrgs(ctx context.Context, orga org.Service) error {
orgIds := []int64{}
for _, or := range user.OrgRoles {
orgIds = append(orgIds, or.OrgId)
}
q := &org.SearchOrgsQuery{}
q.IDs = orgIds
result, err := orga.Search(ctx, q)
if err != nil {
return err
}
orgNamesById := map[int64]string{}
for _, org := range result {
orgNamesById[org.ID] = org.Name
}
for i, orgDTO := range user.OrgRoles {
if orgDTO.OrgId < 1 {
continue
}
orgName := orgNamesById[orgDTO.OrgId]
if orgName != "" {
user.OrgRoles[i].OrgName = orgName
} else {
return errOrganizationNotFound(orgDTO.OrgId)
}
}
return nil
}
// swagger:route POST /admin/ldap/reload admin_ldap reloadLDAPCfg
//
// Reloads the LDAP configuration.
@@ -176,10 +98,10 @@ func (s *Service) ReloadLDAPCfg(c *contextmodel.ReqContext) response.Response {
return response.Error(http.StatusBadRequest, "LDAP is not enabled", nil)
}
err := ldap.ReloadConfig(s.cfg.LDAPConfigFilePath)
if err != nil {
if err := s.ldapService.ReloadConfig(); err != nil {
return response.Error(http.StatusInternalServerError, "Failed to reload LDAP config", err)
}
return response.Success("LDAP config reloaded")
}
@@ -202,18 +124,12 @@ func (s *Service) GetLDAPStatus(c *contextmodel.ReqContext) response.Response {
return response.Error(http.StatusBadRequest, "LDAP is not enabled", nil)
}
ldapConfig, err := getLDAPConfig(s.cfg)
if err != nil {
return response.Error(http.StatusBadRequest, "Failed to obtain the LDAP configuration. Please verify the configuration and try again", err)
}
ldap := newLDAP(ldapConfig.Servers)
if ldap == nil {
ldapClient := s.ldapService.Client()
if ldapClient == nil {
return response.Error(http.StatusInternalServerError, "Failed to find the LDAP server", nil)
}
statuses, err := ldap.Ping()
statuses, err := ldapClient.Ping()
if err != nil {
return response.Error(http.StatusBadRequest, "Failed to connect to the LDAP server(s)", err)
}
@@ -255,9 +171,9 @@ func (s *Service) PostSyncUserWithLDAP(c *contextmodel.ReqContext) response.Resp
return response.Error(http.StatusBadRequest, "LDAP is not enabled", nil)
}
ldapConfig, err := getLDAPConfig(s.cfg)
if err != nil {
return response.Error(http.StatusBadRequest, "Failed to obtain the LDAP configuration. Please verify the configuration and try again", err)
ldapClient := s.ldapService.Client()
if ldapClient == nil {
return response.Error(http.StatusInternalServerError, "Failed to find the LDAP server", nil)
}
userId, err := strconv.ParseInt(web.Params(c.Req)[":id"], 10, 64)
@@ -270,10 +186,10 @@ func (s *Service) PostSyncUserWithLDAP(c *contextmodel.ReqContext) response.Resp
usr, err := s.userService.GetByID(c.Req.Context(), &query)
if err != nil { // validate the userId exists
if errors.Is(err, user.ErrUserNotFound) {
return response.Error(404, user.ErrUserNotFound.Error(), nil)
return response.Error(http.StatusNotFound, user.ErrUserNotFound.Error(), nil)
}
return response.Error(500, "Failed to get user", err)
return response.Error(http.StatusInternalServerError, "Failed to get user", err)
}
authModuleQuery := &login.GetAuthInfoQuery{UserId: usr.ID, AuthModule: login.LDAPAuthModule}
@@ -285,8 +201,7 @@ func (s *Service) PostSyncUserWithLDAP(c *contextmodel.ReqContext) response.Resp
return response.Error(500, "Failed to get user", err)
}
ldapServer := newLDAP(ldapConfig.Servers)
userInfo, _, err := ldapServer.User(usr.Login)
userInfo, _, err := ldapClient.User(usr.Login)
if err != nil {
if errors.Is(err, multildap.ErrDidNotFindUser) { // User was not in the LDAP server - we need to take action:
if s.cfg.AdminUser == usr.Login { // User is *the* Grafana Admin. We cannot disable it.
@@ -351,20 +266,14 @@ func (s *Service) GetUserFromLDAP(c *contextmodel.ReqContext) response.Response
return response.Error(http.StatusBadRequest, "LDAP is not enabled", nil)
}
ldapConfig, err := getLDAPConfig(s.cfg)
if err != nil {
return response.Error(http.StatusBadRequest, "Failed to obtain the LDAP configuration", err)
}
multiLDAP := newLDAP(ldapConfig.Servers)
ldapClient := s.ldapService.Client()
username := web.Params(c.Req)[":username"]
if len(username) == 0 {
return response.Error(http.StatusBadRequest, "Validation error. You must specify an username", nil)
}
user, serverConfig, err := multiLDAP.User(username)
user, serverConfig, err := ldapClient.User(username)
if user == nil || err != nil {
return response.Error(http.StatusNotFound, "No user was found in the LDAP server(s) with that username", err)
}
@@ -409,7 +318,7 @@ func (s *Service) GetUserFromLDAP(c *contextmodel.ReqContext) response.Response
}
s.log.Debug("mapping org roles", "orgsRoles", u.OrgRoles)
if err := u.FetchOrgs(c.Req.Context(), s.orgService); err != nil {
if err := u.fetchOrgs(c.Req.Context(), s.orgService); err != nil {
return response.Error(http.StatusBadRequest, "An organization was not found - Please verify your LDAP configuration", err)
}
@@ -435,16 +344,40 @@ func splitName(name string) (string, string) {
}
}
// swagger:parameters getUserFromLDAP
type GetLDAPUserParams struct {
// in:path
// required:true
UserName string `json:"user_name"`
}
// fetchOrgs fetches the organization(s) information by executing a single query to the database. Then, populating the DTO with the information retrieved.
func (user *LDAPUserDTO) fetchOrgs(ctx context.Context, orga org.Service) error {
orgIds := []int64{}
// swagger:parameters postSyncUserWithLDAP
type SyncLDAPUserParams struct {
// in:path
// required:true
UserID int64 `json:"user_id"`
for _, or := range user.OrgRoles {
orgIds = append(orgIds, or.OrgId)
}
q := &org.SearchOrgsQuery{}
q.IDs = orgIds
result, err := orga.Search(ctx, q)
if err != nil {
return err
}
orgNamesById := map[int64]string{}
for _, org := range result {
orgNamesById[org.ID] = org.Name
}
for i, orgDTO := range user.OrgRoles {
if orgDTO.OrgId < 1 {
continue
}
orgName := orgNamesById[orgDTO.OrgId]
if orgName != "" {
user.OrgRoles[i].OrgName = orgName
} else {
return &OrganizationNotFoundError{orgDTO.OrgId}
}
}
return nil
}
+57 -97
View File
@@ -17,6 +17,7 @@ import (
"github.com/grafana/grafana/pkg/services/auth/authtest"
"github.com/grafana/grafana/pkg/services/ldap"
"github.com/grafana/grafana/pkg/services/ldap/multildap"
"github.com/grafana/grafana/pkg/services/ldap/service"
"github.com/grafana/grafana/pkg/services/login"
"github.com/grafana/grafana/pkg/services/login/logintest"
"github.com/grafana/grafana/pkg/services/org"
@@ -69,6 +70,7 @@ func setupAPITest(t *testing.T, opts ...func(a *Service)) (*Service, *webtest.Se
ldap.ProvideGroupsService(),
&logintest.LoginServiceFake{},
&orgtest.FakeOrgService{},
service.NewLDAPFakeService(),
authtest.NewFakeUserAuthTokenService(),
supportbundlestest.NewFakeBundleService(),
)
@@ -83,20 +85,16 @@ func setupAPITest(t *testing.T, opts ...func(a *Service)) (*Service, *webtest.Se
}
func TestGetUserFromLDAPAPIEndpoint_UserNotFound(t *testing.T) {
getLDAPConfig = func(*setting.Cfg) (*ldap.Config, error) {
return &ldap.Config{}, nil
}
newLDAP = func(_ []*ldap.ServerConfig) multildap.IMultiLDAP {
return &LDAPMock{
UserSearchResult: nil,
}
}
_, server := setupAPITest(t, func(a *Service) {
a.orgService = &orgtest.FakeOrgService{
ExpectedOrgs: []*org.OrgDTO{},
}
a.ldapService = &service.LDAPFakeService{
ExpectedClient: &LDAPMock{
UserSearchResult: nil,
},
ExpectedConfig: &ldap.Config{},
}
})
req := server.NewGetRequest("/api/admin/ldap/user-that-does-not-exist")
@@ -147,13 +145,6 @@ func TestGetUserFromLDAPAPIEndpoint_OrgNotfound(t *testing.T) {
},
}
newLDAP = func(_ []*ldap.ServerConfig) multildap.IMultiLDAP {
return &LDAPMock{
UserSearchResult: userSearchResult,
UserSearchConfig: userSearchConfig,
}
}
mockOrgSearchResult := []*org.OrgDTO{
{ID: 1, Name: "Main Org."},
}
@@ -162,12 +153,15 @@ func TestGetUserFromLDAPAPIEndpoint_OrgNotfound(t *testing.T) {
a.orgService = &orgtest.FakeOrgService{
ExpectedOrgs: mockOrgSearchResult,
}
a.ldapService = &service.LDAPFakeService{
ExpectedClient: &LDAPMock{
UserSearchResult: userSearchResult,
UserSearchConfig: userSearchConfig,
},
ExpectedConfig: &ldap.Config{},
}
})
getLDAPConfig = func(*setting.Cfg) (*ldap.Config, error) {
return &ldap.Config{}, nil
}
req := server.NewGetRequest("/api/admin/ldap/johndoe")
webtest.RequestWithSignedInUser(req, &user.SignedInUser{
OrgID: 1,
@@ -225,21 +219,17 @@ func TestGetUserFromLDAPAPIEndpoint(t *testing.T) {
{ID: 1, Name: "Main Org."},
}
getLDAPConfig = func(*setting.Cfg) (*ldap.Config, error) {
return &ldap.Config{}, nil
}
newLDAP = func(_ []*ldap.ServerConfig) multildap.IMultiLDAP {
return &LDAPMock{
UserSearchResult: userSearchResult,
UserSearchConfig: userSearchConfig,
}
}
_, server := setupAPITest(t, func(a *Service) {
a.orgService = &orgtest.FakeOrgService{
ExpectedOrgs: mockOrgSearchResult,
}
a.ldapService = &service.LDAPFakeService{
ExpectedClient: &LDAPMock{
UserSearchResult: userSearchResult,
UserSearchConfig: userSearchConfig,
},
ExpectedConfig: &ldap.Config{},
}
})
req := server.NewGetRequest("/api/admin/ldap/johndoe")
@@ -314,21 +304,17 @@ func TestGetUserFromLDAPAPIEndpoint_WithTeamHandler(t *testing.T) {
{ID: 1, Name: "Main Org."},
}
getLDAPConfig = func(*setting.Cfg) (*ldap.Config, error) {
return &ldap.Config{}, nil
}
newLDAP = func(_ []*ldap.ServerConfig) multildap.IMultiLDAP {
return &LDAPMock{
UserSearchResult: userSearchResult,
UserSearchConfig: userSearchConfig,
}
}
_, server := setupAPITest(t, func(a *Service) {
a.orgService = &orgtest.FakeOrgService{
ExpectedOrgs: mockOrgSearchResult,
}
a.ldapService = &service.LDAPFakeService{
ExpectedClient: &LDAPMock{
UserSearchResult: userSearchResult,
UserSearchConfig: userSearchConfig,
},
ExpectedConfig: &ldap.Config{},
}
})
req := server.NewGetRequest("/api/admin/ldap/johndoe")
@@ -378,15 +364,11 @@ func TestGetLDAPStatusAPIEndpoint(t *testing.T) {
{Host: "10.0.0.5", Port: 361, Available: false, Error: errors.New("something is awfully wrong")},
}
getLDAPConfig = func(*setting.Cfg) (*ldap.Config, error) {
return &ldap.Config{}, nil
}
newLDAP = func(_ []*ldap.ServerConfig) multildap.IMultiLDAP {
return &LDAPMock{}
}
_, server := setupAPITest(t, func(a *Service) {
a.ldapService = &service.LDAPFakeService{
ExpectedClient: &LDAPMock{},
ExpectedConfig: &ldap.Config{},
}
})
req := server.NewGetRequest("/api/admin/ldap/status")
@@ -418,18 +400,14 @@ func TestPostSyncUserWithLDAPAPIEndpoint_Success(t *testing.T) {
userServiceMock := usertest.NewUserServiceFake()
userServiceMock.ExpectedUser = &user.User{Login: "ldap-daniel", ID: 34}
getLDAPConfig = func(*setting.Cfg) (*ldap.Config, error) {
return &ldap.Config{}, nil
}
newLDAP = func(_ []*ldap.ServerConfig) multildap.IMultiLDAP {
return &LDAPMock{UserSearchResult: &login.ExternalUserInfo{
Login: "ldap-daniel",
}}
}
_, server := setupAPITest(t, func(a *Service) {
a.userService = userServiceMock
a.ldapService = &service.LDAPFakeService{
ExpectedClient: &LDAPMock{UserSearchResult: &login.ExternalUserInfo{
Login: "ldap-daniel",
}},
ExpectedConfig: &ldap.Config{},
}
})
req := server.NewPostRequest("/api/admin/ldap/sync/34", nil)
@@ -459,16 +437,12 @@ func TestPostSyncUserWithLDAPAPIEndpoint_WhenUserNotFound(t *testing.T) {
userServiceMock := usertest.NewUserServiceFake()
userServiceMock.ExpectedError = user.ErrUserNotFound
getLDAPConfig = func(*setting.Cfg) (*ldap.Config, error) {
return &ldap.Config{}, nil
}
newLDAP = func(_ []*ldap.ServerConfig) multildap.IMultiLDAP {
return &LDAPMock{}
}
_, server := setupAPITest(t, func(a *Service) {
a.userService = userServiceMock
a.ldapService = &service.LDAPFakeService{
ExpectedClient: &LDAPMock{},
ExpectedConfig: &ldap.Config{},
}
})
req := server.NewPostRequest("/api/admin/ldap/sync/34", nil)
@@ -498,17 +472,13 @@ func TestPostSyncUserWithLDAPAPIEndpoint_WhenGrafanaAdmin(t *testing.T) {
userServiceMock := usertest.NewUserServiceFake()
userServiceMock.ExpectedUser = &user.User{Login: "ldap-daniel", ID: 34}
getLDAPConfig = func(*setting.Cfg) (*ldap.Config, error) {
return &ldap.Config{}, nil
}
newLDAP = func(_ []*ldap.ServerConfig) multildap.IMultiLDAP {
return &LDAPMock{UserSearchError: multildap.ErrDidNotFindUser}
}
_, server := setupAPITest(t, func(a *Service) {
a.userService = userServiceMock
a.cfg.AdminUser = "ldap-daniel"
a.ldapService = &service.LDAPFakeService{
ExpectedClient: &LDAPMock{UserSearchError: multildap.ErrDidNotFindUser},
ExpectedConfig: &ldap.Config{},
}
})
req := server.NewPostRequest("/api/admin/ldap/sync/34", nil)
@@ -536,17 +506,13 @@ func TestPostSyncUserWithLDAPAPIEndpoint_WhenUserNotInLDAP(t *testing.T) {
userServiceMock := usertest.NewUserServiceFake()
userServiceMock.ExpectedUser = &user.User{Login: "ldap-daniel", ID: 34}
getLDAPConfig = func(*setting.Cfg) (*ldap.Config, error) {
return &ldap.Config{}, nil
}
newLDAP = func(_ []*ldap.ServerConfig) multildap.IMultiLDAP {
return &LDAPMock{UserSearchError: multildap.ErrDidNotFindUser}
}
_, server := setupAPITest(t, func(a *Service) {
a.userService = userServiceMock
a.authInfoService = &logintest.AuthInfoServiceFake{ExpectedExternalUser: &login.ExternalUserInfo{IsDisabled: true, UserId: 34}}
a.ldapService = &service.LDAPFakeService{
ExpectedClient: &LDAPMock{UserSearchError: multildap.ErrDidNotFindUser},
ExpectedConfig: &ldap.Config{},
}
})
req := server.NewPostRequest("/api/admin/ldap/sync/34", nil)
@@ -589,18 +555,6 @@ search_base_dns = ["dc=grafana,dc=org"]`)
errF = f.Close()
require.NoError(t, errF)
getLDAPConfig = func(*setting.Cfg) (*ldap.Config, error) {
return &ldap.Config{}, nil
}
newLDAP = func(_ []*ldap.ServerConfig) multildap.IMultiLDAP {
return &LDAPMock{
UserSearchResult: &login.ExternalUserInfo{
Login: "ldap-daniel",
},
}
}
type testCase struct {
desc string
method string
@@ -688,6 +642,12 @@ search_base_dns = ["dc=grafana,dc=org"]`)
_, server := setupAPITest(t, func(a *Service) {
a.userService = &usertest.FakeUserService{ExpectedUser: &user.User{Login: "ldap-daniel", ID: 1}}
a.cfg.LDAPConfigFilePath = ldapConfigFile
a.ldapService = &service.LDAPFakeService{
ExpectedClient: &LDAPMock{UserSearchResult: &login.ExternalUserInfo{
Login: "ldap-daniel",
}},
ExpectedConfig: &ldap.Config{},
}
})
// Add minimal setup to pass handler
res, err := server.Send(
+6 -8
View File
@@ -9,19 +9,17 @@ import (
"github.com/BurntSushi/toml"
"github.com/grafana/grafana/pkg/services/supportbundles"
"github.com/grafana/grafana/pkg/setting"
)
func (s *Service) supportBundleCollector(context.Context) (*supportbundles.SupportItem, error) {
bWriter := bytes.NewBuffer(nil)
bWriter.WriteString("# LDAP information\n\n")
ldapConfig, err := getLDAPConfig(s.cfg)
ldapConfig := s.ldapService.Config()
if ldapConfig != nil {
bWriter.WriteString("## LDAP Status\n")
ldapClient := newLDAP(ldapConfig.Servers)
ldapClient := s.ldapService.Client()
ldapStatus, err := ldapClient.Ping()
if err != nil {
@@ -66,7 +64,7 @@ func (s *Service) supportBundleCollector(context.Context) (*supportbundles.Suppo
errM := toml.NewEncoder(bWriter).Encode(ldapConfig)
if errM != nil {
bWriter.WriteString(
fmt.Sprintf("Unable to encode LDAP configuration \n Err: %s", err))
fmt.Sprintf("Unable to encode LDAP configuration \n Err: %s", errM))
}
bWriter.WriteString("```\n\n")
@@ -77,9 +75,9 @@ func (s *Service) supportBundleCollector(context.Context) (*supportbundles.Suppo
bWriter.WriteString(fmt.Sprintf("enabled = %v\n", s.cfg.LDAPEnabled))
bWriter.WriteString(fmt.Sprintf("config_file = %s\n", s.cfg.LDAPConfigFilePath))
bWriter.WriteString(fmt.Sprintf("allow_sign_up = %v\n", s.cfg.LDAPAllowSignup))
bWriter.WriteString(fmt.Sprintf("sync_cron = %s\n", setting.LDAPSyncCron))
bWriter.WriteString(fmt.Sprintf("active_sync_enabled = %v\n", setting.LDAPActiveSyncEnabled))
bWriter.WriteString(fmt.Sprintf("skip_org_role_sync = %v\n", setting.LDAPSkipOrgRoleSync))
bWriter.WriteString(fmt.Sprintf("sync_cron = %s\n", s.cfg.LDAPSyncCron))
bWriter.WriteString(fmt.Sprintf("active_sync_enabled = %v\n", s.cfg.LDAPActiveSyncEnabled))
bWriter.WriteString(fmt.Sprintf("skip_org_role_sync = %v\n", s.cfg.LDAPSkipOrgRoleSync))
bWriter.WriteString("```\n\n")