Adding migration support to LDAP from other account types (#3655)

Этот коммит содержится в:
Christopher Speller
2016-07-26 17:39:51 -04:00
коммит произвёл Joram Wilander
родитель 528890dba0
Коммит f5375254f9
8 изменённых файлов: 154 добавлений и 6 удалений

Просмотреть файл

@@ -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 Обычный файл
Просмотреть файл

@@ -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")
}
}