Adding migration support to LDAP from other account types (#3655)
Этот коммит содержится в:
коммит произвёл
Joram Wilander
родитель
528890dba0
Коммит
f5375254f9
5
Makefile
5
Makefile
@@ -182,16 +182,19 @@ ifeq ($(BUILD_ENTERPRISE_READY),true)
|
|||||||
$(GO) test $(GOFLAGS) -run=$(TESTS) -covermode=count -c ./enterprise/compliance && ./compliance.test -test.v -test.timeout=120s -test.coverprofile=ccompliance.out || exit 1
|
$(GO) test $(GOFLAGS) -run=$(TESTS) -covermode=count -c ./enterprise/compliance && ./compliance.test -test.v -test.timeout=120s -test.coverprofile=ccompliance.out || exit 1
|
||||||
$(GO) test $(GOFLAGS) -run=$(TESTS) -covermode=count -c ./enterprise/emoji && ./emoji.test -test.v -test.timeout=120s -test.coverprofile=cemoji.out || exit 1
|
$(GO) test $(GOFLAGS) -run=$(TESTS) -covermode=count -c ./enterprise/emoji && ./emoji.test -test.v -test.timeout=120s -test.coverprofile=cemoji.out || exit 1
|
||||||
$(GO) test $(GOFLAGS) -run=$(TESTS) -covermode=count -c ./enterprise/saml && ./saml.test -test.v -test.timeout=60s -test.coverprofile=csaml.out || exit 1
|
$(GO) test $(GOFLAGS) -run=$(TESTS) -covermode=count -c ./enterprise/saml && ./saml.test -test.v -test.timeout=60s -test.coverprofile=csaml.out || exit 1
|
||||||
|
$(GO) test $(GOFLAGS) -run=$(TESTS) -covermode=count -c ./enterprise/account_migration && ./account_migration.test -test.v -test.timeout=60s -test.coverprofile=caccount_migration.out || exit 1
|
||||||
|
|
||||||
tail -n +2 cldap.out >> ecover.out
|
tail -n +2 cldap.out >> ecover.out
|
||||||
tail -n +2 ccompliance.out >> ecover.out
|
tail -n +2 ccompliance.out >> ecover.out
|
||||||
tail -n +2 cemoji.out >> ecover.out
|
tail -n +2 cemoji.out >> ecover.out
|
||||||
tail -n +2 csaml.out >> ecover.out
|
tail -n +2 csaml.out >> ecover.out
|
||||||
rm -f cldap.out ccompliance.out cemoji.out csaml.out
|
tail -n +2 caccount_migration.out >> ecover.out
|
||||||
|
rm -f cldap.out ccompliance.out cemoji.out csaml.out caccount_migration.out
|
||||||
rm -r ldap.test
|
rm -r ldap.test
|
||||||
rm -r compliance.test
|
rm -r compliance.test
|
||||||
rm -r emoji.test
|
rm -r emoji.test
|
||||||
rm -r saml.test
|
rm -r saml.test
|
||||||
|
rm -r account_migration.test
|
||||||
rm -f config/*.crt
|
rm -f config/*.crt
|
||||||
rm -f config/*.key
|
rm -f config/*.key
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -572,11 +572,7 @@ func ldapSyncNow(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
go func() {
|
go func() {
|
||||||
if utils.IsLicensed && *utils.License.Features.LDAP && *utils.Cfg.LdapSettings.Enable {
|
if utils.IsLicensed && *utils.License.Features.LDAP && *utils.Cfg.LdapSettings.Enable {
|
||||||
if ldapI := einterfaces.GetLdapInterface(); ldapI != nil {
|
if ldapI := einterfaces.GetLdapInterface(); ldapI != nil {
|
||||||
if err := ldapI.Syncronize(); err != nil {
|
ldapI.SyncNow()
|
||||||
l4g.Error("%v", err.Error())
|
|
||||||
} else {
|
|
||||||
l4g.Info(utils.T("ent.ldap.syncdone.info"))
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
l4g.Error("%v", model.NewLocAppError("saveComplianceReport", "ent.compliance.licence_disable.app_error", nil, "").Error())
|
l4g.Error("%v", model.NewLocAppError("saveComplianceReport", "ent.compliance.licence_disable.app_error", nil, "").Error())
|
||||||
}
|
}
|
||||||
|
|||||||
20
einterfaces/account_migration.go
Обычный файл
20
einterfaces/account_migration.go
Обычный файл
@@ -0,0 +1,20 @@
|
|||||||
|
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See License.txt for license information.
|
||||||
|
|
||||||
|
package einterfaces
|
||||||
|
|
||||||
|
import "github.com/mattermost/platform/model"
|
||||||
|
|
||||||
|
type AccountMigrationInterface interface {
|
||||||
|
MigrateToLdap(fromAuthService string, forignUserFieldNameToMatch string) *model.AppError
|
||||||
|
}
|
||||||
|
|
||||||
|
var theAccountMigrationInterface AccountMigrationInterface
|
||||||
|
|
||||||
|
func RegisterAccountMigrationInterface(newInterface AccountMigrationInterface) {
|
||||||
|
theAccountMigrationInterface = newInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetAccountMigrationInterface() AccountMigrationInterface {
|
||||||
|
return theAccountMigrationInterface
|
||||||
|
}
|
||||||
@@ -15,6 +15,8 @@ type LdapInterface interface {
|
|||||||
ValidateFilter(filter string) *model.AppError
|
ValidateFilter(filter string) *model.AppError
|
||||||
Syncronize() *model.AppError
|
Syncronize() *model.AppError
|
||||||
StartLdapSyncJob()
|
StartLdapSyncJob()
|
||||||
|
SyncNow()
|
||||||
|
GetAllLdapUsers() ([]*model.User, *model.AppError)
|
||||||
}
|
}
|
||||||
|
|
||||||
var theLdapInterface LdapInterface
|
var theLdapInterface LdapInterface
|
||||||
|
|||||||
@@ -2099,6 +2099,14 @@
|
|||||||
"id": "cli.license.critical",
|
"id": "cli.license.critical",
|
||||||
"translation": "Feature requires an enterprise license. Please contact your system administrator about upgrading your enterprise license."
|
"translation": "Feature requires an enterprise license. Please contact your system administrator about upgrading your enterprise license."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "ent.migration.migratetoldap.duplicate_field",
|
||||||
|
"translation": "Unable to migrate LDAP users with specified field. Duplicate entry detected. Please remove all duplcates and try again."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ent.migration.migratetoldap.user_not_found",
|
||||||
|
"translation": "Unable to find user on LDAP server: "
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "ent.brand.save_brand_image.decode.app_error",
|
"id": "ent.brand.save_brand_image.decode.app_error",
|
||||||
"translation": "Unable to decode image."
|
"translation": "Unable to decode image."
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ var flagCmdPermanentDeleteTeam bool
|
|||||||
var flagCmdPermanentDeleteAllUsers bool
|
var flagCmdPermanentDeleteAllUsers bool
|
||||||
var flagCmdResetDatabase bool
|
var flagCmdResetDatabase bool
|
||||||
var flagCmdRunLdapSync bool
|
var flagCmdRunLdapSync bool
|
||||||
|
var flagCmdMigrateAccounts bool
|
||||||
var flagUsername string
|
var flagUsername string
|
||||||
var flagCmdUploadLicense bool
|
var flagCmdUploadLicense bool
|
||||||
var flagConfigFile string
|
var flagConfigFile string
|
||||||
@@ -73,6 +74,9 @@ var flagSiteURL string
|
|||||||
var flagConfirmBackup string
|
var flagConfirmBackup string
|
||||||
var flagRole string
|
var flagRole string
|
||||||
var flagRunCmds bool
|
var flagRunCmds bool
|
||||||
|
var flagFromAuth string
|
||||||
|
var flagToAuth string
|
||||||
|
var flagMatchField string
|
||||||
|
|
||||||
func doLoadConfig(filename string) (err string) {
|
func doLoadConfig(filename string) (err string) {
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -288,6 +292,9 @@ func parseCmds() {
|
|||||||
flag.StringVar(&flagChannelName, "channel_name", "", "")
|
flag.StringVar(&flagChannelName, "channel_name", "", "")
|
||||||
flag.StringVar(&flagSiteURL, "site_url", "", "")
|
flag.StringVar(&flagSiteURL, "site_url", "", "")
|
||||||
flag.StringVar(&flagConfirmBackup, "confirm_backup", "", "")
|
flag.StringVar(&flagConfirmBackup, "confirm_backup", "", "")
|
||||||
|
flag.StringVar(&flagFromAuth, "from_auth", "", "")
|
||||||
|
flag.StringVar(&flagToAuth, "to_auth", "", "")
|
||||||
|
flag.StringVar(&flagMatchField, "match_field", "email", "")
|
||||||
flag.StringVar(&flagRole, "role", "", "")
|
flag.StringVar(&flagRole, "role", "", "")
|
||||||
|
|
||||||
flag.BoolVar(&flagCmdUpdateDb30, "upgrade_db_30", false, "")
|
flag.BoolVar(&flagCmdUpdateDb30, "upgrade_db_30", false, "")
|
||||||
@@ -311,6 +318,7 @@ func parseCmds() {
|
|||||||
flag.BoolVar(&flagCmdPermanentDeleteAllUsers, "permanent_delete_all_users", false, "")
|
flag.BoolVar(&flagCmdPermanentDeleteAllUsers, "permanent_delete_all_users", false, "")
|
||||||
flag.BoolVar(&flagCmdResetDatabase, "reset_database", false, "")
|
flag.BoolVar(&flagCmdResetDatabase, "reset_database", false, "")
|
||||||
flag.BoolVar(&flagCmdRunLdapSync, "ldap_sync", false, "")
|
flag.BoolVar(&flagCmdRunLdapSync, "ldap_sync", false, "")
|
||||||
|
flag.BoolVar(&flagCmdMigrateAccounts, "migrate_accounts", false, "")
|
||||||
flag.BoolVar(&flagCmdUploadLicense, "upload_license", false, "")
|
flag.BoolVar(&flagCmdUploadLicense, "upload_license", false, "")
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
@@ -335,6 +343,7 @@ func parseCmds() {
|
|||||||
flagCmdPermanentDeleteAllUsers ||
|
flagCmdPermanentDeleteAllUsers ||
|
||||||
flagCmdResetDatabase ||
|
flagCmdResetDatabase ||
|
||||||
flagCmdRunLdapSync ||
|
flagCmdRunLdapSync ||
|
||||||
|
flagCmdMigrateAccounts ||
|
||||||
flagCmdUploadLicense)
|
flagCmdUploadLicense)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,6 +368,7 @@ func runCmds() {
|
|||||||
cmdResetDatabase()
|
cmdResetDatabase()
|
||||||
cmdUploadLicense()
|
cmdUploadLicense()
|
||||||
cmdRunLdapSync()
|
cmdRunLdapSync()
|
||||||
|
cmdRunMigrateAccounts()
|
||||||
}
|
}
|
||||||
|
|
||||||
type TeamForUpgrade struct {
|
type TeamForUpgrade struct {
|
||||||
@@ -1475,6 +1485,44 @@ func cmdRunLdapSync() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func cmdRunMigrateAccounts() {
|
||||||
|
if flagCmdMigrateAccounts {
|
||||||
|
if len(flagFromAuth) == 0 || (flagFromAuth != "email" && flagFromAuth != "gitlab" && flagFromAuth != "saml") {
|
||||||
|
fmt.Fprintln(os.Stderr, "flag needs an argument: -from_auth")
|
||||||
|
flag.Usage()
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(flagToAuth) == 0 || flagToAuth != "ldap" {
|
||||||
|
fmt.Fprintln(os.Stderr, "flag needs an argument: -from_auth")
|
||||||
|
flag.Usage()
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Email auth in Mattermost system is represented by ""
|
||||||
|
if flagFromAuth == "email" {
|
||||||
|
flagFromAuth = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(flagMatchField) == 0 || (flagMatchField != "email" && flagMatchField != "username") {
|
||||||
|
fmt.Fprintln(os.Stderr, "flag needs an argument: -match_field")
|
||||||
|
flag.Usage()
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if migrate := einterfaces.GetAccountMigrationInterface(); migrate != nil {
|
||||||
|
if err := migrate.MigrateToLdap(flagFromAuth, flagMatchField); err != nil {
|
||||||
|
fmt.Println("ERROR: Account migration failed.")
|
||||||
|
l4g.Error("%v", err.Error())
|
||||||
|
flushLogAndExit(1)
|
||||||
|
} else {
|
||||||
|
fmt.Println("SUCCESS: Account migration complete.")
|
||||||
|
flushLogAndExit(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func cmdUploadLicense() {
|
func cmdUploadLicense() {
|
||||||
if flagCmdUploadLicense {
|
if flagCmdUploadLicense {
|
||||||
if model.BuildEnterpriseReady != "true" {
|
if model.BuildEnterpriseReady != "true" {
|
||||||
@@ -1651,6 +1699,11 @@ COMMANDS:
|
|||||||
|
|
||||||
Example:
|
Example:
|
||||||
platform -upload_license -license="/path/to/license/example.mattermost-license"
|
platform -upload_license -license="/path/to/license/example.mattermost-license"
|
||||||
|
|
||||||
|
-migrate_accounts Migrates accounts from one authentication provider to anouther. Requires -from_auth -to_auth and -match_field flags. Supported options for -from_auth: email, gitlab, saml. Supported options for -to_auth ldap. Supported options for -match_field email, username. Will display any accounts that are not migrated succesfully.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
platform -migrate_accounts -from_auth email -to_auth ldap -match_field username
|
||||||
|
|
||||||
-upgrade_db_30 Upgrades the database from a version 2.x schema to version 3 see
|
-upgrade_db_30 Upgrades the database from a version 2.x schema to version 3 see
|
||||||
http://www.mattermost.org/upgrading-to-mattermost-3-0/
|
http://www.mattermost.org/upgrading-to-mattermost-3-0/
|
||||||
|
|||||||
@@ -84,6 +84,12 @@ func (task *ScheduledTask) Cancel() {
|
|||||||
removeTaskByName(task.Name)
|
removeTaskByName(task.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Executes the task immediatly. A recurring task will be run regularally after interval.
|
||||||
|
func (task *ScheduledTask) Execute() {
|
||||||
|
task.function()
|
||||||
|
task.timer.Reset(task.Interval)
|
||||||
|
}
|
||||||
|
|
||||||
func (task *ScheduledTask) String() string {
|
func (task *ScheduledTask) String() string {
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"%s\nInterval: %s\nRecurring: %t\n",
|
"%s\nInterval: %s\nRecurring: %t\n",
|
||||||
|
|||||||
@@ -126,3 +126,63 @@ func TestGetAllTasks(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestExecuteTask(t *testing.T) {
|
||||||
|
TASK_NAME := "Test Task"
|
||||||
|
TASK_TIME := time.Second * 5
|
||||||
|
|
||||||
|
testValue := 0
|
||||||
|
testFunc := func() {
|
||||||
|
testValue += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
task := CreateTask(TASK_NAME, testFunc, TASK_TIME)
|
||||||
|
if testValue != 0 {
|
||||||
|
t.Fatal("Unexpected execuition of task")
|
||||||
|
}
|
||||||
|
|
||||||
|
task.Execute()
|
||||||
|
|
||||||
|
if testValue != 1 {
|
||||||
|
t.Fatal("Task did not execute")
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(TASK_TIME + time.Second)
|
||||||
|
|
||||||
|
if testValue != 2 {
|
||||||
|
t.Fatal("Task re-executed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExecuteTaskRecurring(t *testing.T) {
|
||||||
|
TASK_NAME := "Test Recurring Task"
|
||||||
|
TASK_TIME := time.Second * 5
|
||||||
|
|
||||||
|
testValue := 0
|
||||||
|
testFunc := func() {
|
||||||
|
testValue += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
task := CreateRecurringTask(TASK_NAME, testFunc, TASK_TIME)
|
||||||
|
if testValue != 0 {
|
||||||
|
t.Fatal("Unexpected execuition of task")
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(time.Second * 3)
|
||||||
|
|
||||||
|
task.Execute()
|
||||||
|
if testValue != 1 {
|
||||||
|
t.Fatal("Task did not execute")
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(time.Second * 3)
|
||||||
|
if testValue != 1 {
|
||||||
|
t.Fatal("Task should not have executed before 5 seconds")
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(time.Second * 3)
|
||||||
|
|
||||||
|
if testValue != 2 {
|
||||||
|
t.Fatal("Task did not re-execute after forced execution")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user