Implement LDAP Certificate (#15361)
* Implement LDAP Certificate * add diagnostics and translations * update from code review * pass pointer to update pict function * pass object to first function * remove debug log messages * update test to add localmode test * update lint errors Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
6fd7cb2a80
Коммит
eba38625eb
112
api4/ldap.go
112
api4/ldap.go
@@ -6,6 +6,7 @@ package api4
|
|||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v5/audit"
|
"github.com/mattermost/mattermost-server/v5/audit"
|
||||||
@@ -32,6 +33,13 @@ func (api *API) InitLdap() {
|
|||||||
|
|
||||||
// DELETE /api/v4/ldap/groups/:remote_id/link
|
// DELETE /api/v4/ldap/groups/:remote_id/link
|
||||||
api.BaseRoutes.LDAP.Handle(`/groups/{remote_id}/link`, api.ApiSessionRequired(unlinkLdapGroup)).Methods("DELETE")
|
api.BaseRoutes.LDAP.Handle(`/groups/{remote_id}/link`, api.ApiSessionRequired(unlinkLdapGroup)).Methods("DELETE")
|
||||||
|
|
||||||
|
api.BaseRoutes.LDAP.Handle("/certificate/public", api.ApiSessionRequired(addLdapPublicCertificate)).Methods("POST")
|
||||||
|
api.BaseRoutes.LDAP.Handle("/certificate/private", api.ApiSessionRequired(addLdapPrivateCertificate)).Methods("POST")
|
||||||
|
|
||||||
|
api.BaseRoutes.LDAP.Handle("/certificate/public", api.ApiSessionRequired(removeLdapPublicCertificate)).Methods("DELETE")
|
||||||
|
api.BaseRoutes.LDAP.Handle("/certificate/private", api.ApiSessionRequired(removeLdapPrivateCertificate)).Methods("DELETE")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func syncLdap(c *Context, w http.ResponseWriter, r *http.Request) {
|
func syncLdap(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -290,3 +298,107 @@ func migrateIdLdap(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
auditRec.Success()
|
auditRec.Success()
|
||||||
ReturnStatusOK(w)
|
ReturnStatusOK(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseLdapCertificateRequest(r *http.Request, maxFileSize int64) (*multipart.FileHeader, *model.AppError) {
|
||||||
|
err := r.ParseMultipartForm(maxFileSize)
|
||||||
|
if err != nil {
|
||||||
|
return nil, model.NewAppError("addLdapCertificate", "api.admin.add_certificate.parseform.app_error", nil, err.Error(), http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
m := r.MultipartForm
|
||||||
|
|
||||||
|
fileArray, ok := m.File["certificate"]
|
||||||
|
if !ok {
|
||||||
|
return nil, model.NewAppError("addLdapCertificate", "api.admin.add_certificate.no_file.app_error", nil, "", http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(fileArray) <= 0 {
|
||||||
|
return nil, model.NewAppError("addLdapCertificate", "api.admin.add_certificate.array.app_error", nil, "", http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileArray[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func addLdapPublicCertificate(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) {
|
||||||
|
c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fileData, err := parseLdapCertificateRequest(r, *c.App.Config().FileSettings.MaxFileSize)
|
||||||
|
if err != nil {
|
||||||
|
c.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
auditRec := c.MakeAuditRecord("addLdapPublicCertificate", audit.Fail)
|
||||||
|
defer c.LogAuditRec(auditRec)
|
||||||
|
auditRec.AddMeta("filename", fileData.Filename)
|
||||||
|
|
||||||
|
if err := c.App.AddLdapPublicCertificate(fileData); err != nil {
|
||||||
|
c.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
auditRec.Success()
|
||||||
|
ReturnStatusOK(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func addLdapPrivateCertificate(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) {
|
||||||
|
c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fileData, err := parseLdapCertificateRequest(r, *c.App.Config().FileSettings.MaxFileSize)
|
||||||
|
if err != nil {
|
||||||
|
c.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
auditRec := c.MakeAuditRecord("addLdapPrivateCertificate", audit.Fail)
|
||||||
|
defer c.LogAuditRec(auditRec)
|
||||||
|
auditRec.AddMeta("filename", fileData.Filename)
|
||||||
|
|
||||||
|
if err := c.App.AddLdapPrivateCertificate(fileData); err != nil {
|
||||||
|
c.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
auditRec.Success()
|
||||||
|
ReturnStatusOK(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeLdapPublicCertificate(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) {
|
||||||
|
c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
auditRec := c.MakeAuditRecord("removeLdapPublicCertificate", audit.Fail)
|
||||||
|
defer c.LogAuditRec(auditRec)
|
||||||
|
|
||||||
|
if err := c.App.RemoveLdapPublicCertificate(); err != nil {
|
||||||
|
c.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
auditRec.Success()
|
||||||
|
ReturnStatusOK(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeLdapPrivateCertificate(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) {
|
||||||
|
c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
auditRec := c.MakeAuditRecord("removeLdapPrivateCertificate", audit.Fail)
|
||||||
|
defer c.LogAuditRec(auditRec)
|
||||||
|
|
||||||
|
if err := c.App.RemoveLdapPrivateCertificate(); err != nil {
|
||||||
|
c.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
auditRec.Success()
|
||||||
|
ReturnStatusOK(w)
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,4 +8,9 @@ func (api *API) InitLdapLocal() {
|
|||||||
api.BaseRoutes.LDAP.Handle("/sync", api.ApiLocal(syncLdap)).Methods("POST")
|
api.BaseRoutes.LDAP.Handle("/sync", api.ApiLocal(syncLdap)).Methods("POST")
|
||||||
api.BaseRoutes.LDAP.Handle("/test", api.ApiLocal(testLdap)).Methods("POST")
|
api.BaseRoutes.LDAP.Handle("/test", api.ApiLocal(testLdap)).Methods("POST")
|
||||||
api.BaseRoutes.LDAP.Handle("/groups", api.ApiLocal(getLdapGroups)).Methods("GET")
|
api.BaseRoutes.LDAP.Handle("/groups", api.ApiLocal(getLdapGroups)).Methods("GET")
|
||||||
|
api.BaseRoutes.LDAP.Handle("/certificate/public", api.ApiLocal(addLdapPublicCertificate)).Methods("POST")
|
||||||
|
api.BaseRoutes.LDAP.Handle("/certificate/private", api.ApiLocal(addLdapPrivateCertificate)).Methods("POST")
|
||||||
|
api.BaseRoutes.LDAP.Handle("/certificate/public", api.ApiLocal(removeLdapPublicCertificate)).Methods("DELETE")
|
||||||
|
api.BaseRoutes.LDAP.Handle("/certificate/private", api.ApiLocal(removeLdapPrivateCertificate)).Methods("DELETE")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,92 @@ import (
|
|||||||
"github.com/mattermost/mattermost-server/v5/model"
|
"github.com/mattermost/mattermost-server/v5/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var spPrivateKey = `-----BEGIN PRIVATE KEY-----
|
||||||
|
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
|
||||||
|
kSU80FrXITorOgZogkDk0FVpJA3qvQ==
|
||||||
|
-----END PRIVATE KEY-----`
|
||||||
|
|
||||||
|
var spPublicCertificate = `-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFijCCA3KgAwIBAgIJAIRQ3EwrvOprMA0GCSqGSIb3DQEBCwUAMFwxCzAJBgNV
|
||||||
|
BAYTAlVTMRIwEAYDVQQHDAlQYWxvIEFsdG8xEzARBgNVBAoMCk1hdHRlcm1vc3Qx
|
||||||
|
DzANBgNVBAsMBkRldk9wczETMBEGA1UEAwwKY2xpZW50LmNvbTAeFw0xOTA5MTIx
|
||||||
|
NzM1MzdaFw0yOTA5MDkxNzM1MzdaMFwxCzAJBgNVBAYTAlVTMRIwEAYDVQQHDAlQ
|
||||||
|
YWxvIEFsdG8xEzARBgNVBAoMCk1hdHRlcm1vc3QxDzANBgNVBAsMBkRldk9wczET
|
||||||
|
MBEGA1UEAwwKY2xpZW50LmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
|
||||||
|
ggIBANtVtR87yAUOCrHDdnuBfmVrJMopdBPrbeHR5Qdej3mMh0CkzIJ2FFihjP05
|
||||||
|
S+jTVpDRTIStzJYpQkTcTRgQ/8yO8EZMh6aaSP81Ba0uojFlkWeXy5VybmA9ZMmA
|
||||||
|
SHPL2Lj8Pj2qiVhqQk5WQr5+cBZTMiI7kYgzoi3zO4Mgr1ryWcsroIZaFZQNHyzq
|
||||||
|
eXE6aIbfYtEo8A4muXE09sMk7lJX9aS17/VR1UJH1xbkWugnlp79xQSkx42mIUwJ
|
||||||
|
zj2AM8Q4s5MCuhizVs6FLiYYCuU7RZlTPftzJlKj8y1YmjZjtuRV6MC3ql0xya9g
|
||||||
|
3LnJ12uyUD7Q6K15lLh03TW0drhCIRo1Vn4N0pZ+kkViqpU02r9gy95SOTshuecm
|
||||||
|
nP7KU5zzM2d6iLATkIj6aYWnRfT5m3UgkPsFdkTDfsmGT5h4F1BSeQc9YoePh2Qo
|
||||||
|
+l+M9f8rWvYbUJjuIMbdXV8+wgUB8JS8ttYf33iFp7PP1T6Fe7z0uaGcqrrfx8N2
|
||||||
|
4ZgpA7JjPz8GxDUxA/mQKsODkeGepTH90QISUWUcKerdn+AehA6JzEDx/UZ4IOIg
|
||||||
|
TZUVhlFAsMvbWVv2jNAEVstll8ZosaZQ+F5xDRGtD9bhg82EG/JcQs6MKwN+7qW2
|
||||||
|
ehvoTwu7Huw2iEW4tpiDQDMNF97OFTRGpZdREqWmKobSpqhbAgMBAAGjTzBNMBIG
|
||||||
|
A1UdEwEB/wQIMAYBAf8CAQAwNwYDVR0RBDAwLoIOd3d3LmNsaWVudC5jb22CEGFk
|
||||||
|
bWluLmNsaWVudC5jb22HBMCoAQqHBAoAAOowDQYJKoZIhvcNAQELBQADggIBAFEI
|
||||||
|
D1ySRS+lQYVm24PPIUH5OmBEJUsVKI/zUXEQ4hdqEqN4UA3NGKkujajTz2fStaOj
|
||||||
|
LfGDup1ZQRYG6VVvNwbZHX9G9mb8TyZ12XFLVjPTbxoG+NZb3ipue9S6qZcT9WEF
|
||||||
|
sjaXhkVNhhVc1GOMnv/FNiclLPWLMnR8WST+Y+WSsT59wP40kJynaT7wQt2TmImg
|
||||||
|
kQfM69jQNgAkyrFwO8y1YcnH7Avrw9YvzhUWG2FfNCTTVNb+StxNtqGwvDV33iZ2
|
||||||
|
bBUWIy2fsNUA4tUYK31Ye6thJiKmvy/LqVJ415gPsI3zHzTCLU/GBUCNCNnEDnhU
|
||||||
|
KO2K3mk1wK3sshMGcda/Xz2a9TfkIxs0pkenS57bZ8xT7mxBzXsZGm7Mnb2fujmX
|
||||||
|
fBEyxQ2ot0Nl9Lp26WrBjQZojJ10Ic2IRxU3spC/FYK7BenQEAdnNHkyQ3lowAto
|
||||||
|
NpOL+j+1ooksPQbp4DeIBbrZDNKvFot+ja2aDJ738sgXf8ht7kGXA5DPNtPLsmUr
|
||||||
|
wpZrhxKD6pXVPhA6EeG2efdUP1ODslmehl4t2yX+FqHChnl7E012W8Cf0Ugybp1t
|
||||||
|
15IXg8GxCRENSNAwpOvTMkoonHqNvBkaCDZHtxeyJMJWQW1B0Xek1JY3CNHvnY7I
|
||||||
|
MCOV5SHi05kD42JSSbmw190VAa4QRGikaeWRhDsj
|
||||||
|
-----END CERTIFICATE-----`
|
||||||
|
|
||||||
func TestTestLdap(t *testing.T) {
|
func TestTestLdap(t *testing.T) {
|
||||||
th := Setup(t)
|
th := Setup(t)
|
||||||
defer th.TearDown()
|
defer th.TearDown()
|
||||||
@@ -112,3 +198,45 @@ func TestMigrateIdLdap(t *testing.T) {
|
|||||||
CheckNotImplementedStatus(t, resp)
|
CheckNotImplementedStatus(t, resp)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUploadPublicCertificate(t *testing.T) {
|
||||||
|
th := Setup(t)
|
||||||
|
defer th.TearDown()
|
||||||
|
|
||||||
|
_, resp := th.Client.UploadLdapPublicCertificate([]byte(spPublicCertificate))
|
||||||
|
require.NotNil(t, resp.Error, "Should have failed. No System Admin privileges")
|
||||||
|
|
||||||
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
||||||
|
_, resp = client.UploadLdapPublicCertificate([]byte(spPrivateKey))
|
||||||
|
require.Nil(t, resp.Error, "Should have passed. System Admin privileges %v", resp.Error)
|
||||||
|
})
|
||||||
|
|
||||||
|
_, resp = th.Client.DeleteLdapPublicCertificate()
|
||||||
|
require.NotNil(t, resp.Error, "Should have failed. No System Admin privileges")
|
||||||
|
|
||||||
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
||||||
|
_, resp := client.DeleteLdapPublicCertificate()
|
||||||
|
require.Nil(t, resp.Error, "Should have passed. System Admin privileges %v", resp.Error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUploadPrivateCertificate(t *testing.T) {
|
||||||
|
th := Setup(t)
|
||||||
|
defer th.TearDown()
|
||||||
|
|
||||||
|
_, resp := th.Client.UploadLdapPrivateCertificate([]byte(spPrivateKey))
|
||||||
|
require.NotNil(t, resp.Error, "Should have failed. No System Admin privileges")
|
||||||
|
|
||||||
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
||||||
|
_, resp = client.UploadLdapPrivateCertificate([]byte(spPrivateKey))
|
||||||
|
require.Nil(t, resp.Error, "Should have passed. System Admin privileges %v", resp.Error)
|
||||||
|
})
|
||||||
|
|
||||||
|
_, resp = th.Client.DeleteLdapPrivateCertificate()
|
||||||
|
require.NotNil(t, resp.Error, "Should have failed. No System Admin privileges")
|
||||||
|
|
||||||
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
||||||
|
_, resp := client.DeleteLdapPrivateCertificate()
|
||||||
|
require.Nil(t, resp.Error, "Should have passed. System Admin privileges %v", resp.Error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -341,6 +341,8 @@ type AppIface interface {
|
|||||||
AddChannelMember(userId string, channel *model.Channel, userRequestorId string, postRootId string) (*model.ChannelMember, *model.AppError)
|
AddChannelMember(userId string, channel *model.Channel, userRequestorId string, postRootId string) (*model.ChannelMember, *model.AppError)
|
||||||
AddConfigListener(listener func(*model.Config, *model.Config)) string
|
AddConfigListener(listener func(*model.Config, *model.Config)) string
|
||||||
AddDirectChannels(teamId string, user *model.User) *model.AppError
|
AddDirectChannels(teamId string, user *model.User) *model.AppError
|
||||||
|
AddLdapPrivateCertificate(fileData *multipart.FileHeader) *model.AppError
|
||||||
|
AddLdapPublicCertificate(fileData *multipart.FileHeader) *model.AppError
|
||||||
AddSamlIdpCertificate(fileData *multipart.FileHeader) *model.AppError
|
AddSamlIdpCertificate(fileData *multipart.FileHeader) *model.AppError
|
||||||
AddSamlPrivateCertificate(fileData *multipart.FileHeader) *model.AppError
|
AddSamlPrivateCertificate(fileData *multipart.FileHeader) *model.AppError
|
||||||
AddSamlPublicCertificate(fileData *multipart.FileHeader) *model.AppError
|
AddSamlPublicCertificate(fileData *multipart.FileHeader) *model.AppError
|
||||||
@@ -807,6 +809,8 @@ type AppIface interface {
|
|||||||
RemoveAllDeactivatedMembersFromChannel(channel *model.Channel) *model.AppError
|
RemoveAllDeactivatedMembersFromChannel(channel *model.Channel) *model.AppError
|
||||||
RemoveConfigListener(id string)
|
RemoveConfigListener(id string)
|
||||||
RemoveFile(path string) *model.AppError
|
RemoveFile(path string) *model.AppError
|
||||||
|
RemoveLdapPrivateCertificate() *model.AppError
|
||||||
|
RemoveLdapPublicCertificate() *model.AppError
|
||||||
RemovePlugin(id string) *model.AppError
|
RemovePlugin(id string) *model.AppError
|
||||||
RemovePluginFromData(data model.PluginEventData)
|
RemovePluginFromData(data model.PluginEventData)
|
||||||
RemoveSamlIdpCertificate() *model.AppError
|
RemoveSamlIdpCertificate() *model.AppError
|
||||||
|
|||||||
97
app/ldap.go
97
app/ldap.go
@@ -4,6 +4,8 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v5/mlog"
|
"github.com/mattermost/mattermost-server/v5/mlog"
|
||||||
@@ -175,3 +177,98 @@ func (a *App) MigrateIdLDAP(toAttribute string) *model.AppError {
|
|||||||
}
|
}
|
||||||
return model.NewAppError("IdMigrateLDAP", "ent.ldap.disabled.app_error", nil, "", http.StatusNotImplemented)
|
return model.NewAppError("IdMigrateLDAP", "ent.ldap.disabled.app_error", nil, "", http.StatusNotImplemented)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) writeLdapFile(filename string, fileData *multipart.FileHeader) *model.AppError {
|
||||||
|
file, err := fileData.Open()
|
||||||
|
if err != nil {
|
||||||
|
return model.NewAppError("AddLdapCertificate", "api.admin.add_certificate.open.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
data, err := ioutil.ReadAll(file)
|
||||||
|
if err != nil {
|
||||||
|
return model.NewAppError("AddLdapCertificate", "api.admin.add_certificate.saving.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = a.Srv().configStore.SetFile(filename, data)
|
||||||
|
if err != nil {
|
||||||
|
return model.NewAppError("AddLdapCertificate", "api.admin.add_certificate.saving.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) AddLdapPublicCertificate(fileData *multipart.FileHeader) *model.AppError {
|
||||||
|
if err := a.writeLdapFile(model.LDAP_PUBIC_CERTIFICATE_NAME, fileData); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := a.Config().Clone()
|
||||||
|
*cfg.LdapSettings.PublicCertificateFile = model.LDAP_PUBIC_CERTIFICATE_NAME
|
||||||
|
|
||||||
|
if err := cfg.IsValid(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
a.UpdateConfig(func(dest *model.Config) { *dest = *cfg })
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) AddLdapPrivateCertificate(fileData *multipart.FileHeader) *model.AppError {
|
||||||
|
if err := a.writeLdapFile(model.LDAP_PRIVATE_KEY_NAME, fileData); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := a.Config().Clone()
|
||||||
|
*cfg.LdapSettings.PrivateKeyFile = model.LDAP_PRIVATE_KEY_NAME
|
||||||
|
|
||||||
|
if err := cfg.IsValid(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
a.UpdateConfig(func(dest *model.Config) { *dest = *cfg })
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) removeLdapFile(filename string) *model.AppError {
|
||||||
|
if err := a.Srv().configStore.RemoveFile(filename); err != nil {
|
||||||
|
return model.NewAppError("RemoveLdapFile", "api.admin.remove_certificate.delete.app_error", map[string]interface{}{"Filename": filename}, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) RemoveLdapPublicCertificate() *model.AppError {
|
||||||
|
if err := a.removeLdapFile(*a.Config().LdapSettings.PublicCertificateFile); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := a.Config().Clone()
|
||||||
|
*cfg.LdapSettings.PublicCertificateFile = ""
|
||||||
|
|
||||||
|
if err := cfg.IsValid(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
a.UpdateConfig(func(dest *model.Config) { *dest = *cfg })
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) RemoveLdapPrivateCertificate() *model.AppError {
|
||||||
|
if err := a.removeLdapFile(*a.Config().LdapSettings.PrivateKeyFile); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := a.Config().Clone()
|
||||||
|
*cfg.LdapSettings.PrivateKeyFile = ""
|
||||||
|
|
||||||
|
if err := cfg.IsValid(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
a.UpdateConfig(func(dest *model.Config) { *dest = *cfg })
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ func (a *App) DoLogin(w http.ResponseWriter, r *http.Request, user *model.User,
|
|||||||
|
|
||||||
if a.Srv().License() != nil && *a.Srv().License().Features.LDAP && a.Ldap() != nil {
|
if a.Srv().License() != nil && *a.Srv().License().Features.LDAP && a.Ldap() != nil {
|
||||||
a.Srv().Go(func() {
|
a.Srv().Go(func() {
|
||||||
a.Ldap().UpdateProfilePictureIfNecessary(user, session)
|
a.Ldap().UpdateProfilePictureIfNecessary(*user, session)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -170,6 +170,50 @@ func (a *OpenTracingAppLayer) AddDirectChannels(teamId string, user *model.User)
|
|||||||
return resultVar0
|
return resultVar0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *OpenTracingAppLayer) AddLdapPrivateCertificate(fileData *multipart.FileHeader) *model.AppError {
|
||||||
|
origCtx := a.ctx
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.AddLdapPrivateCertificate")
|
||||||
|
|
||||||
|
a.ctx = newCtx
|
||||||
|
a.app.Srv().Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
a.app.Srv().Store.SetContext(origCtx)
|
||||||
|
a.ctx = origCtx
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0 := a.app.AddLdapPrivateCertificate(fileData)
|
||||||
|
|
||||||
|
if resultVar0 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar0))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *OpenTracingAppLayer) AddLdapPublicCertificate(fileData *multipart.FileHeader) *model.AppError {
|
||||||
|
origCtx := a.ctx
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.AddLdapPublicCertificate")
|
||||||
|
|
||||||
|
a.ctx = newCtx
|
||||||
|
a.app.Srv().Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
a.app.Srv().Store.SetContext(origCtx)
|
||||||
|
a.ctx = origCtx
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0 := a.app.AddLdapPublicCertificate(fileData)
|
||||||
|
|
||||||
|
if resultVar0 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar0))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0
|
||||||
|
}
|
||||||
|
|
||||||
func (a *OpenTracingAppLayer) AddPublicKey(name string, key io.Reader) *model.AppError {
|
func (a *OpenTracingAppLayer) AddPublicKey(name string, key io.Reader) *model.AppError {
|
||||||
origCtx := a.ctx
|
origCtx := a.ctx
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.AddPublicKey")
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.AddPublicKey")
|
||||||
@@ -11340,6 +11384,50 @@ func (a *OpenTracingAppLayer) RemoveFile(path string) *model.AppError {
|
|||||||
return resultVar0
|
return resultVar0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *OpenTracingAppLayer) RemoveLdapPrivateCertificate() *model.AppError {
|
||||||
|
origCtx := a.ctx
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.RemoveLdapPrivateCertificate")
|
||||||
|
|
||||||
|
a.ctx = newCtx
|
||||||
|
a.app.Srv().Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
a.app.Srv().Store.SetContext(origCtx)
|
||||||
|
a.ctx = origCtx
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0 := a.app.RemoveLdapPrivateCertificate()
|
||||||
|
|
||||||
|
if resultVar0 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar0))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *OpenTracingAppLayer) RemoveLdapPublicCertificate() *model.AppError {
|
||||||
|
origCtx := a.ctx
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.RemoveLdapPublicCertificate")
|
||||||
|
|
||||||
|
a.ctx = newCtx
|
||||||
|
a.app.Srv().Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
a.app.Srv().Store.SetContext(origCtx)
|
||||||
|
a.ctx = origCtx
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0 := a.app.RemoveLdapPublicCertificate()
|
||||||
|
|
||||||
|
if resultVar0 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar0))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0
|
||||||
|
}
|
||||||
|
|
||||||
func (a *OpenTracingAppLayer) RemovePlugin(id string) *model.AppError {
|
func (a *OpenTracingAppLayer) RemovePlugin(id string) *model.AppError {
|
||||||
origCtx := a.ctx
|
origCtx := a.ctx
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.RemovePlugin")
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.RemovePlugin")
|
||||||
|
|||||||
@@ -21,6 +21,6 @@ type LdapInterface interface {
|
|||||||
GetGroup(groupUID string) (*model.Group, *model.AppError)
|
GetGroup(groupUID string) (*model.Group, *model.AppError)
|
||||||
GetAllGroupsPage(page int, perPage int, opts model.LdapGroupSearchOpts) ([]*model.Group, int, *model.AppError)
|
GetAllGroupsPage(page int, perPage int, opts model.LdapGroupSearchOpts) ([]*model.Group, int, *model.AppError)
|
||||||
FirstLoginSync(userID, userAuthService, userAuthData, email string) *model.AppError
|
FirstLoginSync(userID, userAuthService, userAuthData, email string) *model.AppError
|
||||||
UpdateProfilePictureIfNecessary(*model.User, *model.Session)
|
UpdateProfilePictureIfNecessary(model.User, *model.Session)
|
||||||
GetADLdapIdFromSAMLId(authData string) string
|
GetADLdapIdFromSAMLId(authData string) string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -305,6 +305,6 @@ func (_m *LdapInterface) SwitchToLdap(userId string, ldapId string, ldapPassword
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdateProfilePictureIfNecessary provides a mock function with given fields: _a0, _a1
|
// UpdateProfilePictureIfNecessary provides a mock function with given fields: _a0, _a1
|
||||||
func (_m *LdapInterface) UpdateProfilePictureIfNecessary(_a0 *model.User, _a1 *model.Session) {
|
func (_m *LdapInterface) UpdateProfilePictureIfNecessary(_a0 model.User, _a1 *model.Session) {
|
||||||
_m.Called(_a0, _a1)
|
_m.Called(_a0, _a1)
|
||||||
}
|
}
|
||||||
|
|||||||
16
i18n/en.json
16
i18n/en.json
@@ -59,6 +59,10 @@
|
|||||||
"id": "api.admin.add_certificate.open.app_error",
|
"id": "api.admin.add_certificate.open.app_error",
|
||||||
"translation": "Could not open certificate file."
|
"translation": "Could not open certificate file."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "api.admin.add_certificate.parseform.app_error",
|
||||||
|
"translation": "Error parsing multiform request"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "api.admin.add_certificate.saving.app_error",
|
"id": "api.admin.add_certificate.saving.app_error",
|
||||||
"translation": "Could not save certificate file."
|
"translation": "Could not save certificate file."
|
||||||
@@ -5490,10 +5494,18 @@
|
|||||||
"id": "ent.ldap.do_login.bind_admin_user.app_error",
|
"id": "ent.ldap.do_login.bind_admin_user.app_error",
|
||||||
"translation": "Unable to bind to AD/LDAP server. Check BindUsername and BindPassword."
|
"translation": "Unable to bind to AD/LDAP server. Check BindUsername and BindPassword."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "ent.ldap.do_login.certificate.app_error",
|
||||||
|
"translation": "Error loading LDAP TLS Certificate file."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "ent.ldap.do_login.invalid_password.app_error",
|
"id": "ent.ldap.do_login.invalid_password.app_error",
|
||||||
"translation": "Invalid Password."
|
"translation": "Invalid Password."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "ent.ldap.do_login.key.app_error",
|
||||||
|
"translation": "Error loading LDAP TLS Key file."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "ent.ldap.do_login.licence_disable.app_error",
|
"id": "ent.ldap.do_login.licence_disable.app_error",
|
||||||
"translation": "AD/LDAP functionality disabled by current license. Please contact your system administrator about upgrading your enterprise license."
|
"translation": "AD/LDAP functionality disabled by current license. Please contact your system administrator about upgrading your enterprise license."
|
||||||
@@ -5518,6 +5530,10 @@
|
|||||||
"id": "ent.ldap.do_login.user_not_registered.app_error",
|
"id": "ent.ldap.do_login.user_not_registered.app_error",
|
||||||
"translation": "User not registered on AD/LDAP server."
|
"translation": "User not registered on AD/LDAP server."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "ent.ldap.do_login.x509.app_error",
|
||||||
|
"translation": "Error creating key pair"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "ent.ldap.save_user.email_exists.ldap_app_error",
|
"id": "ent.ldap.save_user.email_exists.ldap_app_error",
|
||||||
"translation": "This account does not use AD/LDAP authentication. Please sign in using email and password."
|
"translation": "This account does not use AD/LDAP authentication. Please sign in using email and password."
|
||||||
|
|||||||
@@ -3671,7 +3671,7 @@ func (c *Client4) GetSamlMetadata() (string, *Response) {
|
|||||||
return buf.String(), BuildResponse(r)
|
return buf.String(), BuildResponse(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func samlFileToMultipart(data []byte, filename string) ([]byte, *multipart.Writer, error) {
|
func fileToMultipart(data []byte, filename string) ([]byte, *multipart.Writer, error) {
|
||||||
body := &bytes.Buffer{}
|
body := &bytes.Buffer{}
|
||||||
writer := multipart.NewWriter(body)
|
writer := multipart.NewWriter(body)
|
||||||
|
|
||||||
@@ -3694,7 +3694,7 @@ func samlFileToMultipart(data []byte, filename string) ([]byte, *multipart.Write
|
|||||||
// UploadSamlIdpCertificate will upload an IDP certificate for SAML and set the config to use it.
|
// UploadSamlIdpCertificate will upload an IDP certificate for SAML and set the config to use it.
|
||||||
// The filename parameter is deprecated and ignored: the server will pick a hard-coded filename when writing to disk.
|
// The filename parameter is deprecated and ignored: the server will pick a hard-coded filename when writing to disk.
|
||||||
func (c *Client4) UploadSamlIdpCertificate(data []byte, filename string) (bool, *Response) {
|
func (c *Client4) UploadSamlIdpCertificate(data []byte, filename string) (bool, *Response) {
|
||||||
body, writer, err := samlFileToMultipart(data, filename)
|
body, writer, err := fileToMultipart(data, filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, &Response{Error: NewAppError("UploadSamlIdpCertificate", "model.client.upload_saml_cert.app_error", nil, err.Error(), http.StatusBadRequest)}
|
return false, &Response{Error: NewAppError("UploadSamlIdpCertificate", "model.client.upload_saml_cert.app_error", nil, err.Error(), http.StatusBadRequest)}
|
||||||
}
|
}
|
||||||
@@ -3706,7 +3706,7 @@ func (c *Client4) UploadSamlIdpCertificate(data []byte, filename string) (bool,
|
|||||||
// UploadSamlPublicCertificate will upload a public certificate for SAML and set the config to use it.
|
// UploadSamlPublicCertificate will upload a public certificate for SAML and set the config to use it.
|
||||||
// The filename parameter is deprecated and ignored: the server will pick a hard-coded filename when writing to disk.
|
// The filename parameter is deprecated and ignored: the server will pick a hard-coded filename when writing to disk.
|
||||||
func (c *Client4) UploadSamlPublicCertificate(data []byte, filename string) (bool, *Response) {
|
func (c *Client4) UploadSamlPublicCertificate(data []byte, filename string) (bool, *Response) {
|
||||||
body, writer, err := samlFileToMultipart(data, filename)
|
body, writer, err := fileToMultipart(data, filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, &Response{Error: NewAppError("UploadSamlPublicCertificate", "model.client.upload_saml_cert.app_error", nil, err.Error(), http.StatusBadRequest)}
|
return false, &Response{Error: NewAppError("UploadSamlPublicCertificate", "model.client.upload_saml_cert.app_error", nil, err.Error(), http.StatusBadRequest)}
|
||||||
}
|
}
|
||||||
@@ -3718,7 +3718,7 @@ func (c *Client4) UploadSamlPublicCertificate(data []byte, filename string) (boo
|
|||||||
// UploadSamlPrivateCertificate will upload a private key for SAML and set the config to use it.
|
// UploadSamlPrivateCertificate will upload a private key for SAML and set the config to use it.
|
||||||
// The filename parameter is deprecated and ignored: the server will pick a hard-coded filename when writing to disk.
|
// The filename parameter is deprecated and ignored: the server will pick a hard-coded filename when writing to disk.
|
||||||
func (c *Client4) UploadSamlPrivateCertificate(data []byte, filename string) (bool, *Response) {
|
func (c *Client4) UploadSamlPrivateCertificate(data []byte, filename string) (bool, *Response) {
|
||||||
body, writer, err := samlFileToMultipart(data, filename)
|
body, writer, err := fileToMultipart(data, filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, &Response{Error: NewAppError("UploadSamlPrivateCertificate", "model.client.upload_saml_cert.app_error", nil, err.Error(), http.StatusBadRequest)}
|
return false, &Response{Error: NewAppError("UploadSamlPrivateCertificate", "model.client.upload_saml_cert.app_error", nil, err.Error(), http.StatusBadRequest)}
|
||||||
}
|
}
|
||||||
@@ -4079,6 +4079,48 @@ func (c *Client4) MigrateAuthToSaml(fromAuthService string, usersMap map[string]
|
|||||||
return CheckStatusOK(r), BuildResponse(r)
|
return CheckStatusOK(r), BuildResponse(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UploadLdapPublicCertificate will upload a public certificate for LDAP and set the config to use it.
|
||||||
|
func (c *Client4) UploadLdapPublicCertificate(data []byte) (bool, *Response) {
|
||||||
|
body, writer, err := fileToMultipart(data, LDAP_PUBIC_CERTIFICATE_NAME)
|
||||||
|
if err != nil {
|
||||||
|
return false, &Response{Error: NewAppError("UploadLdapPublicCertificate", "model.client.upload_ldap_cert.app_error", nil, err.Error(), http.StatusBadRequest)}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, resp := c.DoUploadFile(c.GetLdapRoute()+"/certificate/public", body, writer.FormDataContentType())
|
||||||
|
return resp.Error == nil, resp
|
||||||
|
}
|
||||||
|
|
||||||
|
// UploadLdapPrivateCertificate will upload a private key for LDAP and set the config to use it.
|
||||||
|
func (c *Client4) UploadLdapPrivateCertificate(data []byte) (bool, *Response) {
|
||||||
|
body, writer, err := fileToMultipart(data, LDAP_PRIVATE_KEY_NAME)
|
||||||
|
if err != nil {
|
||||||
|
return false, &Response{Error: NewAppError("UploadLdapPrivateCertificate", "model.client.upload_Ldap_cert.app_error", nil, err.Error(), http.StatusBadRequest)}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, resp := c.DoUploadFile(c.GetLdapRoute()+"/certificate/private", body, writer.FormDataContentType())
|
||||||
|
return resp.Error == nil, resp
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteLdapPublicCertificate deletes the LDAP IDP certificate from the server and updates the config to not use it and disable LDAP.
|
||||||
|
func (c *Client4) DeleteLdapPublicCertificate() (bool, *Response) {
|
||||||
|
r, err := c.DoApiDelete(c.GetLdapRoute() + "/certificate/public")
|
||||||
|
if err != nil {
|
||||||
|
return false, BuildErrorResponse(r, err)
|
||||||
|
}
|
||||||
|
defer closeBody(r)
|
||||||
|
return CheckStatusOK(r), BuildResponse(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteLDAPPrivateCertificate deletes the LDAP IDP certificate from the server and updates the config to not use it and disable LDAP.
|
||||||
|
func (c *Client4) DeleteLdapPrivateCertificate() (bool, *Response) {
|
||||||
|
r, err := c.DoApiDelete(c.GetLdapRoute() + "/certificate/private")
|
||||||
|
if err != nil {
|
||||||
|
return false, BuildErrorResponse(r, err)
|
||||||
|
}
|
||||||
|
defer closeBody(r)
|
||||||
|
return CheckStatusOK(r), BuildResponse(r)
|
||||||
|
}
|
||||||
|
|
||||||
// Audits Section
|
// Audits Section
|
||||||
|
|
||||||
// GetAudits returns a list of audits for the whole system.
|
// GetAudits returns a list of audits for the whole system.
|
||||||
|
|||||||
@@ -1943,9 +1943,11 @@ type LdapSettings struct {
|
|||||||
SyncIntervalMinutes *int `access:"authentication"`
|
SyncIntervalMinutes *int `access:"authentication"`
|
||||||
|
|
||||||
// Advanced
|
// Advanced
|
||||||
SkipCertificateVerification *bool `access:"authentication"`
|
SkipCertificateVerification *bool `access:"authentication"`
|
||||||
QueryTimeout *int `access:"authentication"`
|
PublicCertificateFile *string `access:"authentication"`
|
||||||
MaxPageSize *int `access:"authentication"`
|
PrivateKeyFile *string `access:"authentication"`
|
||||||
|
QueryTimeout *int `access:"authentication"`
|
||||||
|
MaxPageSize *int `access:"authentication"`
|
||||||
|
|
||||||
// Customization
|
// Customization
|
||||||
LoginFieldName *string `access:"authentication"`
|
LoginFieldName *string `access:"authentication"`
|
||||||
@@ -1983,6 +1985,14 @@ func (s *LdapSettings) SetDefaults() {
|
|||||||
s.ConnectionSecurity = NewString("")
|
s.ConnectionSecurity = NewString("")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.PublicCertificateFile == nil {
|
||||||
|
s.PublicCertificateFile = NewString("")
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.PrivateKeyFile == nil {
|
||||||
|
s.PrivateKeyFile = NewString("")
|
||||||
|
}
|
||||||
|
|
||||||
if s.BaseDN == nil {
|
if s.BaseDN == nil {
|
||||||
s.BaseDN = NewString("")
|
s.BaseDN = NewString("")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,5 +4,7 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
const (
|
const (
|
||||||
USER_AUTH_SERVICE_LDAP = "ldap"
|
USER_AUTH_SERVICE_LDAP = "ldap"
|
||||||
|
LDAP_PUBIC_CERTIFICATE_NAME = "ldap-public.crt"
|
||||||
|
LDAP_PRIVATE_KEY_NAME = "ldap-private.key"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -606,6 +606,8 @@ func (ts *TelemetryService) trackConfig() {
|
|||||||
"isempty_guest_filter": isDefault(*cfg.LdapSettings.GuestFilter, ""),
|
"isempty_guest_filter": isDefault(*cfg.LdapSettings.GuestFilter, ""),
|
||||||
"isempty_admin_filter": isDefault(*cfg.LdapSettings.AdminFilter, ""),
|
"isempty_admin_filter": isDefault(*cfg.LdapSettings.AdminFilter, ""),
|
||||||
"isnotempty_picture_attribute": !isDefault(*cfg.LdapSettings.PictureAttribute, ""),
|
"isnotempty_picture_attribute": !isDefault(*cfg.LdapSettings.PictureAttribute, ""),
|
||||||
|
"isnotempty_public_certificate": !isDefault(*cfg.LdapSettings.PublicCertificateFile, ""),
|
||||||
|
"isnotempty_private_key": !isDefault(*cfg.LdapSettings.PrivateKeyFile, ""),
|
||||||
})
|
})
|
||||||
|
|
||||||
ts.sendTelemetry(TRACK_CONFIG_COMPLIANCE, map[string]interface{}{
|
ts.sendTelemetry(TRACK_CONFIG_COMPLIANCE, map[string]interface{}{
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user