Adding LDAP Syncronization (#3219)
Этот коммит содержится в:
коммит произвёл
Joram Wilander
родитель
87f357a54d
Коммит
ea3342aa6c
2
Makefile
2
Makefile
@@ -160,7 +160,7 @@ test-server: start-docker prepare-enterprise
|
||||
echo "mode: count" > cover.out
|
||||
|
||||
$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=340s -covermode=count -coverprofile=capi.out ./api || exit 1
|
||||
$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=12s -covermode=count -coverprofile=cmodel.out ./model || exit 1
|
||||
$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=60s -covermode=count -coverprofile=cmodel.out ./model || exit 1
|
||||
$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=180s -covermode=count -coverprofile=cstore.out ./store || exit 1
|
||||
$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=120s -covermode=count -coverprofile=cutils.out ./utils || exit 1
|
||||
$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=120s -covermode=count -coverprofile=cweb.out ./web || exit 1
|
||||
|
||||
23
api/user.go
23
api/user.go
@@ -704,6 +704,7 @@ func RevokeSessionById(c *Context, sessionId string) {
|
||||
}
|
||||
}
|
||||
|
||||
// IF YOU UPDATE THIS PLEASE UPDATE BELOW
|
||||
func RevokeAllSession(c *Context, userId string) {
|
||||
if result := <-Srv.Store.Session().GetSessions(userId); result.Err != nil {
|
||||
c.Err = result.Err
|
||||
@@ -726,6 +727,28 @@ func RevokeAllSession(c *Context, userId string) {
|
||||
}
|
||||
}
|
||||
|
||||
// UGH...
|
||||
// If you update this please update above
|
||||
func RevokeAllSessionsNoContext(userId string) *model.AppError {
|
||||
if result := <-Srv.Store.Session().GetSessions(userId); result.Err != nil {
|
||||
return result.Err
|
||||
} else {
|
||||
sessions := result.Data.([]*model.Session)
|
||||
|
||||
for _, session := range sessions {
|
||||
if session.IsOAuth {
|
||||
RevokeAccessToken(session.Token)
|
||||
} else {
|
||||
sessionCache.Remove(session.Token)
|
||||
if result := <-Srv.Store.Session().Remove(session.Id); result.Err != nil {
|
||||
return result.Err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getSessions(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
params := mux.Vars(r)
|
||||
|
||||
@@ -147,6 +147,7 @@
|
||||
"UsernameAttribute": "",
|
||||
"NicknameAttribute": "",
|
||||
"IdAttribute": "",
|
||||
"SyncIntervalMinutes": 60,
|
||||
"SkipCertificateVerification": false,
|
||||
"QueryTimeout": 60,
|
||||
"LoginFieldName": ""
|
||||
|
||||
@@ -13,6 +13,8 @@ type LdapInterface interface {
|
||||
CheckPassword(id string, password string) *model.AppError
|
||||
SwitchToLdap(userId, ldapId, ldapPassword string) *model.AppError
|
||||
ValidateFilter(filter string) *model.AppError
|
||||
Syncronize() *model.AppError
|
||||
StartLdapSyncJob()
|
||||
}
|
||||
|
||||
var theLdapInterface LdapInterface
|
||||
|
||||
16
i18n/en.json
16
i18n/en.json
@@ -2027,6 +2027,14 @@
|
||||
"id": "ent.ldap.validate_filter.app_error",
|
||||
"translation": "Invalid LDAP Filter"
|
||||
},
|
||||
{
|
||||
"id": "ent.ldap.syncronize.get_all.app_error",
|
||||
"translation": "Unable to get all users using LDAP"
|
||||
},
|
||||
{
|
||||
"id": "ent.ldap.syncdone.info",
|
||||
"translation": "LDAP Synchronization completed"
|
||||
},
|
||||
{
|
||||
"id": "ent.mfa.activate.authenticate.app_error",
|
||||
"translation": "Error attempting to authenticate MFA token"
|
||||
@@ -2411,6 +2419,10 @@
|
||||
"id": "model.config.is_valid.ldap_security.app_error",
|
||||
"translation": "Invalid connection security for LDAP settings. Must be '', 'TLS', or 'STARTTLS'"
|
||||
},
|
||||
{
|
||||
"id": "model.config.is_valid.ldap_sync_interval.app_error",
|
||||
"translation": "Invalid sync interval time. Must be at least one minute."
|
||||
},
|
||||
{
|
||||
"id": "model.config.is_valid.listen_address.app_error",
|
||||
"translation": "Invalid listen address for service settings Must be set."
|
||||
@@ -3555,6 +3567,10 @@
|
||||
"id": "store.sql_user.get_by_auth.other.app_error",
|
||||
"translation": "We encountered an error trying to find the account by authentication type."
|
||||
},
|
||||
{
|
||||
"id": "store.sql_user.get_all_using_auth_service.other.app_error",
|
||||
"translation": "We encountered an error trying to find all the accounts using a specific authentication type."
|
||||
},
|
||||
{
|
||||
"id": "store.sql_user.get_by_username.app_error",
|
||||
"translation": "We couldn't find an existing account matching your username for this team. This team may require an invite from the team owner to join."
|
||||
|
||||
164
mattermost.go
164
mattermost.go
@@ -55,6 +55,7 @@ var flagCmdPermanentDeleteUser bool
|
||||
var flagCmdPermanentDeleteTeam bool
|
||||
var flagCmdPermanentDeleteAllUsers bool
|
||||
var flagCmdResetDatabase bool
|
||||
var flagCmdRunLdapSync bool
|
||||
var flagUsername string
|
||||
var flagCmdUploadLicense bool
|
||||
var flagConfigFile string
|
||||
@@ -125,8 +126,12 @@ func main() {
|
||||
setDiagnosticId()
|
||||
go runSecurityAndDiagnosticsJob()
|
||||
|
||||
if einterfaces.GetComplianceInterface() != nil {
|
||||
einterfaces.GetComplianceInterface().StartComplianceDailyJob()
|
||||
if complianceI := einterfaces.GetComplianceInterface(); complianceI != nil {
|
||||
complianceI.StartComplianceDailyJob()
|
||||
}
|
||||
|
||||
if ldapI := einterfaces.GetLdapInterface(); ldapI != nil {
|
||||
ldapI.StartLdapSyncJob()
|
||||
}
|
||||
|
||||
// wait for kill signal before attempting to gracefully shutdown
|
||||
@@ -154,96 +159,97 @@ func setDiagnosticId() {
|
||||
}
|
||||
}
|
||||
|
||||
func runSecurityAndDiagnosticsJob() {
|
||||
for {
|
||||
if *utils.Cfg.ServiceSettings.EnableSecurityFixAlert {
|
||||
if result := <-api.Srv.Store.System().Get(); result.Err == nil {
|
||||
props := result.Data.(model.StringMap)
|
||||
lastSecurityTime, _ := strconv.ParseInt(props[model.SYSTEM_LAST_SECURITY_TIME], 10, 0)
|
||||
currentTime := model.GetMillis()
|
||||
func doSecurityAndDiagnostics() {
|
||||
if *utils.Cfg.ServiceSettings.EnableSecurityFixAlert {
|
||||
if result := <-api.Srv.Store.System().Get(); result.Err == nil {
|
||||
props := result.Data.(model.StringMap)
|
||||
lastSecurityTime, _ := strconv.ParseInt(props[model.SYSTEM_LAST_SECURITY_TIME], 10, 0)
|
||||
currentTime := model.GetMillis()
|
||||
|
||||
if (currentTime - lastSecurityTime) > 1000*60*60*24*1 {
|
||||
l4g.Debug(utils.T("mattermost.security_checks.debug"))
|
||||
if (currentTime - lastSecurityTime) > 1000*60*60*24*1 {
|
||||
l4g.Debug(utils.T("mattermost.security_checks.debug"))
|
||||
|
||||
v := url.Values{}
|
||||
v := url.Values{}
|
||||
|
||||
v.Set(utils.PROP_DIAGNOSTIC_ID, utils.CfgDiagnosticId)
|
||||
v.Set(utils.PROP_DIAGNOSTIC_BUILD, model.CurrentVersion+"."+model.BuildNumber)
|
||||
v.Set(utils.PROP_DIAGNOSTIC_ENTERPRISE_READY, model.BuildEnterpriseReady)
|
||||
v.Set(utils.PROP_DIAGNOSTIC_DATABASE, utils.Cfg.SqlSettings.DriverName)
|
||||
v.Set(utils.PROP_DIAGNOSTIC_OS, runtime.GOOS)
|
||||
v.Set(utils.PROP_DIAGNOSTIC_CATEGORY, utils.VAL_DIAGNOSTIC_CATEGORY_DEFAULT)
|
||||
v.Set(utils.PROP_DIAGNOSTIC_ID, utils.CfgDiagnosticId)
|
||||
v.Set(utils.PROP_DIAGNOSTIC_BUILD, model.CurrentVersion+"."+model.BuildNumber)
|
||||
v.Set(utils.PROP_DIAGNOSTIC_ENTERPRISE_READY, model.BuildEnterpriseReady)
|
||||
v.Set(utils.PROP_DIAGNOSTIC_DATABASE, utils.Cfg.SqlSettings.DriverName)
|
||||
v.Set(utils.PROP_DIAGNOSTIC_OS, runtime.GOOS)
|
||||
v.Set(utils.PROP_DIAGNOSTIC_CATEGORY, utils.VAL_DIAGNOSTIC_CATEGORY_DEFAULT)
|
||||
|
||||
if len(props[model.SYSTEM_RAN_UNIT_TESTS]) > 0 {
|
||||
v.Set(utils.PROP_DIAGNOSTIC_UNIT_TESTS, "1")
|
||||
} else {
|
||||
v.Set(utils.PROP_DIAGNOSTIC_UNIT_TESTS, "0")
|
||||
}
|
||||
if len(props[model.SYSTEM_RAN_UNIT_TESTS]) > 0 {
|
||||
v.Set(utils.PROP_DIAGNOSTIC_UNIT_TESTS, "1")
|
||||
} else {
|
||||
v.Set(utils.PROP_DIAGNOSTIC_UNIT_TESTS, "0")
|
||||
}
|
||||
|
||||
systemSecurityLastTime := &model.System{Name: model.SYSTEM_LAST_SECURITY_TIME, Value: strconv.FormatInt(currentTime, 10)}
|
||||
if lastSecurityTime == 0 {
|
||||
<-api.Srv.Store.System().Save(systemSecurityLastTime)
|
||||
} else {
|
||||
<-api.Srv.Store.System().Update(systemSecurityLastTime)
|
||||
}
|
||||
systemSecurityLastTime := &model.System{Name: model.SYSTEM_LAST_SECURITY_TIME, Value: strconv.FormatInt(currentTime, 10)}
|
||||
if lastSecurityTime == 0 {
|
||||
<-api.Srv.Store.System().Save(systemSecurityLastTime)
|
||||
} else {
|
||||
<-api.Srv.Store.System().Update(systemSecurityLastTime)
|
||||
}
|
||||
|
||||
if ucr := <-api.Srv.Store.User().GetTotalUsersCount(); ucr.Err == nil {
|
||||
v.Set(utils.PROP_DIAGNOSTIC_USER_COUNT, strconv.FormatInt(ucr.Data.(int64), 10))
|
||||
}
|
||||
if ucr := <-api.Srv.Store.User().GetTotalUsersCount(); ucr.Err == nil {
|
||||
v.Set(utils.PROP_DIAGNOSTIC_USER_COUNT, strconv.FormatInt(ucr.Data.(int64), 10))
|
||||
}
|
||||
|
||||
if ucr := <-api.Srv.Store.User().GetTotalActiveUsersCount(); ucr.Err == nil {
|
||||
v.Set(utils.PROP_DIAGNOSTIC_ACTIVE_USER_COUNT, strconv.FormatInt(ucr.Data.(int64), 10))
|
||||
}
|
||||
if ucr := <-api.Srv.Store.User().GetTotalActiveUsersCount(); ucr.Err == nil {
|
||||
v.Set(utils.PROP_DIAGNOSTIC_ACTIVE_USER_COUNT, strconv.FormatInt(ucr.Data.(int64), 10))
|
||||
}
|
||||
|
||||
res, err := http.Get(utils.DIAGNOSTIC_URL + "/security?" + v.Encode())
|
||||
if err != nil {
|
||||
l4g.Error(utils.T("mattermost.security_info.error"))
|
||||
return
|
||||
}
|
||||
res, err := http.Get(utils.DIAGNOSTIC_URL + "/security?" + v.Encode())
|
||||
if err != nil {
|
||||
l4g.Error(utils.T("mattermost.security_info.error"))
|
||||
return
|
||||
}
|
||||
|
||||
bulletins := model.SecurityBulletinsFromJson(res.Body)
|
||||
bulletins := model.SecurityBulletinsFromJson(res.Body)
|
||||
|
||||
for _, bulletin := range bulletins {
|
||||
if bulletin.AppliesToVersion == model.CurrentVersion {
|
||||
if props["SecurityBulletin_"+bulletin.Id] == "" {
|
||||
if results := <-api.Srv.Store.User().GetSystemAdminProfiles(); results.Err != nil {
|
||||
l4g.Error(utils.T("mattermost.system_admins.error"))
|
||||
for _, bulletin := range bulletins {
|
||||
if bulletin.AppliesToVersion == model.CurrentVersion {
|
||||
if props["SecurityBulletin_"+bulletin.Id] == "" {
|
||||
if results := <-api.Srv.Store.User().GetSystemAdminProfiles(); results.Err != nil {
|
||||
l4g.Error(utils.T("mattermost.system_admins.error"))
|
||||
return
|
||||
} else {
|
||||
users := results.Data.(map[string]*model.User)
|
||||
|
||||
resBody, err := http.Get(utils.DIAGNOSTIC_URL + "/bulletins/" + bulletin.Id)
|
||||
if err != nil {
|
||||
l4g.Error(utils.T("mattermost.security_bulletin.error"))
|
||||
return
|
||||
} else {
|
||||
users := results.Data.(map[string]*model.User)
|
||||
|
||||
resBody, err := http.Get(utils.DIAGNOSTIC_URL + "/bulletins/" + bulletin.Id)
|
||||
if err != nil {
|
||||
l4g.Error(utils.T("mattermost.security_bulletin.error"))
|
||||
return
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resBody.Body)
|
||||
res.Body.Close()
|
||||
if err != nil || resBody.StatusCode != 200 {
|
||||
l4g.Error(utils.T("mattermost.security_bulletin_read.error"))
|
||||
return
|
||||
}
|
||||
|
||||
for _, user := range users {
|
||||
l4g.Info(utils.T("mattermost.send_bulletin.info"), bulletin.Id, user.Email)
|
||||
utils.SendMail(user.Email, utils.T("mattermost.bulletin.subject"), string(body))
|
||||
}
|
||||
}
|
||||
|
||||
bulletinSeen := &model.System{Name: "SecurityBulletin_" + bulletin.Id, Value: bulletin.Id}
|
||||
<-api.Srv.Store.System().Save(bulletinSeen)
|
||||
body, err := ioutil.ReadAll(resBody.Body)
|
||||
res.Body.Close()
|
||||
if err != nil || resBody.StatusCode != 200 {
|
||||
l4g.Error(utils.T("mattermost.security_bulletin_read.error"))
|
||||
return
|
||||
}
|
||||
|
||||
for _, user := range users {
|
||||
l4g.Info(utils.T("mattermost.send_bulletin.info"), bulletin.Id, user.Email)
|
||||
utils.SendMail(user.Email, utils.T("mattermost.bulletin.subject"), string(body))
|
||||
}
|
||||
}
|
||||
|
||||
bulletinSeen := &model.System{Name: "SecurityBulletin_" + bulletin.Id, Value: bulletin.Id}
|
||||
<-api.Srv.Store.System().Save(bulletinSeen)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
time.Sleep(time.Hour * 4)
|
||||
}
|
||||
}
|
||||
|
||||
func runSecurityAndDiagnosticsJob() {
|
||||
doSecurityAndDiagnostics()
|
||||
model.CreateRecurringTask("Security and Diagnostics", doSecurityAndDiagnostics, time.Hour*4)
|
||||
}
|
||||
|
||||
func parseCmds() {
|
||||
flag.Usage = func() {
|
||||
fmt.Fprintln(os.Stderr, usage)
|
||||
@@ -272,6 +278,7 @@ func parseCmds() {
|
||||
flag.BoolVar(&flagCmdPermanentDeleteTeam, "permanent_delete_team", false, "")
|
||||
flag.BoolVar(&flagCmdPermanentDeleteAllUsers, "permanent_delete_all_users", false, "")
|
||||
flag.BoolVar(&flagCmdResetDatabase, "reset_database", false, "")
|
||||
flag.BoolVar(&flagCmdRunLdapSync, "ldap_sync", false, "")
|
||||
flag.BoolVar(&flagCmdUploadLicense, "upload_license", false, "")
|
||||
|
||||
flag.Parse()
|
||||
@@ -290,6 +297,7 @@ func parseCmds() {
|
||||
flagCmdPermanentDeleteTeam ||
|
||||
flagCmdPermanentDeleteAllUsers ||
|
||||
flagCmdResetDatabase ||
|
||||
flagCmdRunLdapSync ||
|
||||
flagCmdUploadLicense)
|
||||
}
|
||||
|
||||
@@ -308,6 +316,7 @@ func runCmds() {
|
||||
cmdPermDeleteAllUsers()
|
||||
cmdResetDatabase()
|
||||
cmdUploadLicense()
|
||||
cmdRunLdapSync()
|
||||
}
|
||||
|
||||
type TeamForUpgrade struct {
|
||||
@@ -1130,6 +1139,21 @@ func cmdResetDatabase() {
|
||||
|
||||
}
|
||||
|
||||
func cmdRunLdapSync() {
|
||||
if flagCmdRunLdapSync {
|
||||
if ldapI := einterfaces.GetLdapInterface(); ldapI != nil {
|
||||
if err := ldapI.Syncronize(); err != nil {
|
||||
fmt.Println("ERROR: Ldap Syncronization Failed")
|
||||
l4g.Error("%v", err.Error())
|
||||
flushLogAndExit(1)
|
||||
} else {
|
||||
fmt.Println("SUCCESS: Ldap Syncronization Complete")
|
||||
flushLogAndExit(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func cmdUploadLicense() {
|
||||
if flagCmdUploadLicense {
|
||||
if model.BuildEnterpriseReady != "true" {
|
||||
|
||||
@@ -190,6 +190,9 @@ type LdapSettings struct {
|
||||
NicknameAttribute *string
|
||||
IdAttribute *string
|
||||
|
||||
// Syncronization
|
||||
SyncIntervalMinutes *int
|
||||
|
||||
// Advanced
|
||||
SkipCertificateVerification *bool
|
||||
QueryTimeout *int
|
||||
@@ -441,6 +444,11 @@ func (o *Config) SetDefaults() {
|
||||
*o.LdapSettings.LoginFieldName = ""
|
||||
}
|
||||
|
||||
if o.LdapSettings.SyncIntervalMinutes == nil {
|
||||
o.LdapSettings.SyncIntervalMinutes = new(int)
|
||||
*o.LdapSettings.SyncIntervalMinutes = 60
|
||||
}
|
||||
|
||||
if o.ServiceSettings.SessionLengthWebInDays == nil {
|
||||
o.ServiceSettings.SessionLengthWebInDays = new(int)
|
||||
*o.ServiceSettings.SessionLengthWebInDays = 30
|
||||
@@ -635,6 +643,10 @@ func (o *Config) IsValid() *AppError {
|
||||
return NewLocAppError("Config.IsValid", "model.config.is_valid.ldap_security.app_error", nil, "")
|
||||
}
|
||||
|
||||
if *o.LdapSettings.SyncIntervalMinutes <= 0 {
|
||||
return NewLocAppError("Config.IsValid", "model.config.is_valid.ldap_sync_interval.app_error", nil, "")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
91
model/job.go
Обычный файл
91
model/job.go
Обычный файл
@@ -0,0 +1,91 @@
|
||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
type TaskFunc func()
|
||||
|
||||
type ScheduledTask struct {
|
||||
Name string `json:"name"`
|
||||
Interval time.Duration `json:"interval"`
|
||||
Recurring bool `json:"recurring"`
|
||||
function TaskFunc `json:",omitempty"`
|
||||
timer *time.Timer `json:",omitempty"`
|
||||
}
|
||||
|
||||
var tasks = make(map[string]*ScheduledTask)
|
||||
|
||||
func addTask(task *ScheduledTask) {
|
||||
tasks[task.Name] = task
|
||||
}
|
||||
|
||||
func removeTaskByName(name string) {
|
||||
delete(tasks, name)
|
||||
}
|
||||
|
||||
func getTaskByName(name string) *ScheduledTask {
|
||||
return tasks[name]
|
||||
}
|
||||
|
||||
func GetAllTasks() *map[string]*ScheduledTask {
|
||||
return &tasks
|
||||
}
|
||||
|
||||
func CreateTask(name string, function TaskFunc, timeToExecution time.Duration) *ScheduledTask {
|
||||
task := &ScheduledTask{
|
||||
Name: name,
|
||||
Interval: timeToExecution,
|
||||
Recurring: false,
|
||||
function: function,
|
||||
}
|
||||
|
||||
taskRunner := func() {
|
||||
go task.function()
|
||||
removeTaskByName(task.Name)
|
||||
}
|
||||
|
||||
task.timer = time.AfterFunc(timeToExecution, taskRunner)
|
||||
|
||||
addTask(task)
|
||||
|
||||
return task
|
||||
}
|
||||
|
||||
func CreateRecurringTask(name string, function TaskFunc, interval time.Duration) *ScheduledTask {
|
||||
task := &ScheduledTask{
|
||||
Name: name,
|
||||
Interval: interval,
|
||||
Recurring: true,
|
||||
function: function,
|
||||
}
|
||||
|
||||
taskRecurer := func() {
|
||||
go task.function()
|
||||
task.timer.Reset(task.Interval)
|
||||
}
|
||||
|
||||
task.timer = time.AfterFunc(interval, taskRecurer)
|
||||
|
||||
addTask(task)
|
||||
|
||||
return task
|
||||
}
|
||||
|
||||
func (task *ScheduledTask) Cancel() {
|
||||
task.timer.Stop()
|
||||
removeTaskByName(task.Name)
|
||||
}
|
||||
|
||||
func (task *ScheduledTask) String() string {
|
||||
return fmt.Sprintf(
|
||||
"%s\nInterval: %s\nRecurring: %t\n",
|
||||
task.Name,
|
||||
task.Interval.String(),
|
||||
task.Recurring,
|
||||
)
|
||||
}
|
||||
128
model/job_test.go
Обычный файл
128
model/job_test.go
Обычный файл
@@ -0,0 +1,128 @@
|
||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestCreateTask(t *testing.T) {
|
||||
TASK_NAME := "Test Task"
|
||||
TASK_TIME := time.Second * 3
|
||||
|
||||
testValue := 0
|
||||
testFunc := func() {
|
||||
testValue = 1
|
||||
}
|
||||
|
||||
task := CreateTask(TASK_NAME, testFunc, TASK_TIME)
|
||||
if testValue != 0 {
|
||||
t.Fatal("Unexpected execuition of task")
|
||||
}
|
||||
|
||||
time.Sleep(TASK_TIME + time.Second)
|
||||
|
||||
if testValue != 1 {
|
||||
t.Fatal("Task did not execute")
|
||||
}
|
||||
|
||||
if task.Name != TASK_NAME {
|
||||
t.Fatal("Bad name")
|
||||
}
|
||||
|
||||
if task.Interval != TASK_TIME {
|
||||
t.Fatal("Bad interval")
|
||||
}
|
||||
|
||||
if task.Recurring != false {
|
||||
t.Fatal("should not reccur")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateRecurringTask(t *testing.T) {
|
||||
TASK_NAME := "Test Recurring Task"
|
||||
TASK_TIME := time.Second * 3
|
||||
|
||||
testValue := 0
|
||||
testFunc := func() {
|
||||
testValue += 1
|
||||
}
|
||||
|
||||
task := CreateRecurringTask(TASK_NAME, testFunc, TASK_TIME)
|
||||
if testValue != 0 {
|
||||
t.Fatal("Unexpected execuition of task")
|
||||
}
|
||||
|
||||
time.Sleep(TASK_TIME + time.Second)
|
||||
|
||||
if testValue != 1 {
|
||||
t.Fatal("Task did not execute")
|
||||
}
|
||||
|
||||
time.Sleep(TASK_TIME)
|
||||
|
||||
if testValue != 2 {
|
||||
t.Fatal("Task did not re-execute")
|
||||
}
|
||||
|
||||
if task.Name != TASK_NAME {
|
||||
t.Fatal("Bad name")
|
||||
}
|
||||
|
||||
if task.Interval != TASK_TIME {
|
||||
t.Fatal("Bad interval")
|
||||
}
|
||||
|
||||
if task.Recurring != true {
|
||||
t.Fatal("should reccur")
|
||||
}
|
||||
|
||||
task.Cancel()
|
||||
}
|
||||
|
||||
func TestCancelTask(t *testing.T) {
|
||||
TASK_NAME := "Test Task"
|
||||
TASK_TIME := time.Second * 3
|
||||
|
||||
testValue := 0
|
||||
testFunc := func() {
|
||||
testValue = 1
|
||||
}
|
||||
|
||||
task := CreateTask(TASK_NAME, testFunc, TASK_TIME)
|
||||
if testValue != 0 {
|
||||
t.Fatal("Unexpected execuition of task")
|
||||
}
|
||||
task.Cancel()
|
||||
|
||||
time.Sleep(TASK_TIME + time.Second)
|
||||
|
||||
if testValue != 0 {
|
||||
t.Fatal("Unexpected execuition of task")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAllTasks(t *testing.T) {
|
||||
doNothing := func() {}
|
||||
|
||||
CreateTask("Task1", doNothing, time.Hour)
|
||||
CreateTask("Task2", doNothing, time.Second)
|
||||
CreateRecurringTask("Task3", doNothing, time.Second)
|
||||
task4 := CreateRecurringTask("Task4", doNothing, time.Second)
|
||||
|
||||
task4.Cancel()
|
||||
|
||||
time.Sleep(time.Second * 3)
|
||||
|
||||
tasks := *GetAllTasks()
|
||||
if len(tasks) != 2 {
|
||||
t.Fatal("Wrong number of tasks got: ", len(tasks))
|
||||
}
|
||||
for _, task := range tasks {
|
||||
if task.Name != "Task1" && task.Name != "Task3" {
|
||||
t.Fatal("Wrong tasks")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -793,6 +793,27 @@ func (us SqlUserStore) GetByAuth(authData *string, authService string) StoreChan
|
||||
return storeChannel
|
||||
}
|
||||
|
||||
func (us SqlUserStore) GetAllUsingAuthService(authService string) StoreChannel {
|
||||
|
||||
storeChannel := make(StoreChannel)
|
||||
|
||||
go func() {
|
||||
result := StoreResult{}
|
||||
var data []*model.User
|
||||
|
||||
if _, err := us.GetReplica().Select(&data, "SELECT * FROM Users WHERE AuthService = :AuthService", map[string]interface{}{"AuthService": authService}); err != nil {
|
||||
result.Err = model.NewLocAppError("SqlUserStore.GetByAuth", "store.sql_user.get_by_auth.other.app_error", nil, "authService="+authService+", "+err.Error())
|
||||
}
|
||||
|
||||
result.Data = data
|
||||
|
||||
storeChannel <- result
|
||||
close(storeChannel)
|
||||
}()
|
||||
|
||||
return storeChannel
|
||||
}
|
||||
|
||||
func (us SqlUserStore) GetByUsername(username string) StoreChannel {
|
||||
|
||||
storeChannel := make(StoreChannel)
|
||||
|
||||
@@ -139,6 +139,7 @@ type UserStore interface {
|
||||
GetProfileByIds(userId []string) StoreChannel
|
||||
GetByEmail(email string) StoreChannel
|
||||
GetByAuth(authData *string, authService string) StoreChannel
|
||||
GetAllUsingAuthService(authService string) StoreChannel
|
||||
GetByUsername(username string) StoreChannel
|
||||
GetForLogin(loginId string, allowSignInWithUsername, allowSignInWithEmail, ldapEnabled bool) StoreChannel
|
||||
VerifyEmail(userId string) StoreChannel
|
||||
|
||||
@@ -36,6 +36,7 @@ export default class LdapSettings extends AdminSettings {
|
||||
emailAttribute: props.config.LdapSettings.EmailAttribute,
|
||||
usernameAttribute: props.config.LdapSettings.UsernameAttribute,
|
||||
idAttribute: props.config.LdapSettings.IdAttribute,
|
||||
syncIntervalMinutes: props.config.LdapSettings.SyncIntervalMinutes,
|
||||
skipCertificateVerification: props.config.LdapSettings.SkipCertificateVerification,
|
||||
queryTimeout: props.config.LdapSettings.QueryTimeout,
|
||||
loginFieldName: props.config.LdapSettings.LoginFieldName
|
||||
@@ -57,6 +58,7 @@ export default class LdapSettings extends AdminSettings {
|
||||
config.LdapSettings.EmailAttribute = this.state.emailAttribute;
|
||||
config.LdapSettings.UsernameAttribute = this.state.usernameAttribute;
|
||||
config.LdapSettings.IdAttribute = this.state.idAttribute;
|
||||
config.LdapSettings.SyncIntervalMinutes = this.parseIntNonZero(this.state.syncIntervalMinutes);
|
||||
config.LdapSettings.SkipCertificateVerification = this.state.skipCertificateVerification;
|
||||
config.LdapSettings.QueryTimeout = this.parseIntNonZero(this.state.queryTimeout);
|
||||
config.LdapSettings.LoginFieldName = this.state.loginFieldName;
|
||||
@@ -339,6 +341,24 @@ export default class LdapSettings extends AdminSettings {
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.enable}
|
||||
/>
|
||||
<TextSetting
|
||||
id='syncIntervalMinutes'
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='admin.ldap.syncIntervalTitle'
|
||||
defaultMessage='Synchronization Interval (In Minutes)'
|
||||
/>
|
||||
}
|
||||
helpText={
|
||||
<FormattedMessage
|
||||
id='admin.ldap.syncIntervalHelpText'
|
||||
defaultMessage='LDAP Synchronization is the process by which Mattermost updates its users to reflect any updated data on the LDAP server. For example if a name for a user is updated on the LDAP server, the change will be reflected in Mattermost when the synchronization is performed. Accounts that have been removed from the LDAP server will have their active sessions cleared and no longer be able to login to Mattermost. Mattermost will perform this synchronization regularly according to the interval supplied here. For example, if 60 is supplied, Mattermost will update the users every hour.'
|
||||
/>
|
||||
}
|
||||
value={this.state.syncIntervalMinutes}
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.enable}
|
||||
/>
|
||||
<BooleanSetting
|
||||
id='skipCertificateVerification'
|
||||
label={
|
||||
|
||||
@@ -286,6 +286,8 @@
|
||||
"admin.ldap.userFilterTitle": "User Filter:",
|
||||
"admin.ldap.usernameAttrEx": "Ex \"sAMAccountName\"",
|
||||
"admin.ldap.usernameAttrTitle": "Username Attribute:",
|
||||
"admin.ldap.syncIntervalTitle": "Synchronization Interval (In Minutes)",
|
||||
"admin.ldap.syncIntervalHelpText": "LDAP Synchronization is the process by which Mattermost updates its users to reflect any updated data on the LDAP server. For example if a name for a user is updated on the LDAP server, the change will be reflected in Mattermost when the synchronization is performed. Accounts that have been removed from the LDAP server will have their active sessions cleared and no longer be able to login to Mattermost. Mattermost will perform this synchronization regularly according to the interval supplied here. For example, if 60 is supplied, Mattermost will update the users every hour.",
|
||||
"admin.license.choose": "Choose File",
|
||||
"admin.license.chooseFile": "Choose File",
|
||||
"admin.license.edition": "Edition: ",
|
||||
|
||||
Ссылка в новой задаче
Block a user