mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
* 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>
275 lines
8.0 KiB
Go
275 lines
8.0 KiB
Go
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
package app
|
|
|
|
import (
|
|
"io/ioutil"
|
|
"mime/multipart"
|
|
"net/http"
|
|
|
|
"github.com/mattermost/mattermost-server/v5/mlog"
|
|
"github.com/mattermost/mattermost-server/v5/model"
|
|
"github.com/mattermost/mattermost-server/v5/utils"
|
|
)
|
|
|
|
func (a *App) SyncLdap() {
|
|
a.Srv().Go(func() {
|
|
|
|
if license := a.Srv().License(); license != nil && *license.Features.LDAP && *a.Config().LdapSettings.EnableSync {
|
|
if ldapI := a.Ldap(); ldapI != nil {
|
|
ldapI.StartSynchronizeJob(false)
|
|
} else {
|
|
mlog.Error("Not executing ldap sync because ldap is not available")
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func (a *App) TestLdap() *model.AppError {
|
|
license := a.Srv().License()
|
|
if ldapI := a.Ldap(); ldapI != nil && license != nil && *license.Features.LDAP && (*a.Config().LdapSettings.Enable || *a.Config().LdapSettings.EnableSync) {
|
|
if err := ldapI.RunTest(); err != nil {
|
|
err.StatusCode = 500
|
|
return err
|
|
}
|
|
} else {
|
|
err := model.NewAppError("TestLdap", "ent.ldap.disabled.app_error", nil, "", http.StatusNotImplemented)
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetLdapGroup retrieves a single LDAP group by the given LDAP group id.
|
|
func (a *App) GetLdapGroup(ldapGroupID string) (*model.Group, *model.AppError) {
|
|
var group *model.Group
|
|
|
|
if a.Ldap() != nil {
|
|
var err *model.AppError
|
|
group, err = a.Ldap().GetGroup(ldapGroupID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
} else {
|
|
ae := model.NewAppError("GetLdapGroup", "ent.ldap.app_error", nil, "", http.StatusNotImplemented)
|
|
mlog.Error("Unable to use ldap", mlog.String("ldap_group_id", ldapGroupID), mlog.Err(ae))
|
|
return nil, ae
|
|
}
|
|
|
|
return group, nil
|
|
}
|
|
|
|
// GetAllLdapGroupsPage retrieves all LDAP groups under the configured base DN using the default or configured group
|
|
// filter.
|
|
func (a *App) GetAllLdapGroupsPage(page int, perPage int, opts model.LdapGroupSearchOpts) ([]*model.Group, int, *model.AppError) {
|
|
var groups []*model.Group
|
|
var total int
|
|
|
|
if a.Ldap() != nil {
|
|
var err *model.AppError
|
|
groups, total, err = a.Ldap().GetAllGroupsPage(page, perPage, opts)
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
} else {
|
|
ae := model.NewAppError("GetAllLdapGroupsPage", "ent.ldap.app_error", nil, "", http.StatusNotImplemented)
|
|
mlog.Error("Unable to use ldap", mlog.Err(ae))
|
|
return nil, 0, ae
|
|
}
|
|
|
|
return groups, total, nil
|
|
}
|
|
|
|
func (a *App) SwitchEmailToLdap(email, password, code, ldapLoginId, ldapPassword string) (string, *model.AppError) {
|
|
if a.Srv().License() != nil && !*a.Config().ServiceSettings.ExperimentalEnableAuthenticationTransfer {
|
|
return "", model.NewAppError("emailToLdap", "api.user.email_to_ldap.not_available.app_error", nil, "", http.StatusForbidden)
|
|
}
|
|
|
|
user, err := a.GetUserByEmail(email)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if err := a.CheckPasswordAndAllCriteria(user, password, code); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if err := a.RevokeAllSessions(user.Id); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
ldapInterface := a.Ldap()
|
|
if ldapInterface == nil {
|
|
return "", model.NewAppError("SwitchEmailToLdap", "api.user.email_to_ldap.not_available.app_error", nil, "", http.StatusNotImplemented)
|
|
}
|
|
|
|
if err := ldapInterface.SwitchToLdap(user.Id, ldapLoginId, ldapPassword); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
a.Srv().Go(func() {
|
|
if err := a.Srv().EmailService.SendSignInChangeEmail(user.Email, "AD/LDAP", user.Locale, a.GetSiteURL()); err != nil {
|
|
mlog.Error(err.Error())
|
|
}
|
|
})
|
|
|
|
return "/login?extra=signin_change", nil
|
|
}
|
|
|
|
func (a *App) SwitchLdapToEmail(ldapPassword, code, email, newPassword string) (string, *model.AppError) {
|
|
if a.Srv().License() != nil && !*a.Config().ServiceSettings.ExperimentalEnableAuthenticationTransfer {
|
|
return "", model.NewAppError("ldapToEmail", "api.user.ldap_to_email.not_available.app_error", nil, "", http.StatusForbidden)
|
|
}
|
|
|
|
user, err := a.GetUserByEmail(email)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if user.AuthService != model.USER_AUTH_SERVICE_LDAP {
|
|
return "", model.NewAppError("SwitchLdapToEmail", "api.user.ldap_to_email.not_ldap_account.app_error", nil, "", http.StatusBadRequest)
|
|
}
|
|
|
|
ldapInterface := a.Ldap()
|
|
if ldapInterface == nil || user.AuthData == nil {
|
|
return "", model.NewAppError("SwitchLdapToEmail", "api.user.ldap_to_email.not_available.app_error", nil, "", http.StatusNotImplemented)
|
|
}
|
|
|
|
if err := ldapInterface.CheckPasswordAuthData(*user.AuthData, ldapPassword); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if err := a.CheckUserMfa(user, code); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if err := a.UpdatePassword(user, newPassword); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if err := a.RevokeAllSessions(user.Id); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
T := utils.GetUserTranslations(user.Locale)
|
|
|
|
a.Srv().Go(func() {
|
|
if err := a.Srv().EmailService.SendSignInChangeEmail(user.Email, T("api.templates.signin_change_email.body.method_email"), user.Locale, a.GetSiteURL()); err != nil {
|
|
mlog.Error(err.Error())
|
|
}
|
|
})
|
|
|
|
return "/login?extra=signin_change", nil
|
|
}
|
|
|
|
func (a *App) MigrateIdLDAP(toAttribute string) *model.AppError {
|
|
if ldapI := a.Ldap(); ldapI != nil {
|
|
if err := ldapI.MigrateIDAttribute(toAttribute); err != nil {
|
|
switch err := err.(type) {
|
|
case *model.AppError:
|
|
return err
|
|
default:
|
|
return model.NewAppError("IdMigrateLDAP", "ent.ldap_id_migrate.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
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
|
|
}
|