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/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/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 ccompliance.out >> ecover.out
tail -n +2 cemoji.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 compliance.test
rm -r emoji.test
rm -r saml.test
rm -r account_migration.test
rm -f config/*.crt
rm -f config/*.key
endif

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

@@ -572,11 +572,7 @@ func ldapSyncNow(c *Context, w http.ResponseWriter, r *http.Request) {
go func() {
if utils.IsLicensed && *utils.License.Features.LDAP && *utils.Cfg.LdapSettings.Enable {
if ldapI := einterfaces.GetLdapInterface(); ldapI != nil {
if err := ldapI.Syncronize(); err != nil {
l4g.Error("%v", err.Error())
} else {
l4g.Info(utils.T("ent.ldap.syncdone.info"))
}
ldapI.SyncNow()
} else {
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
Syncronize() *model.AppError
StartLdapSyncJob()
SyncNow()
GetAllLdapUsers() ([]*model.User, *model.AppError)
}
var theLdapInterface LdapInterface

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

@@ -2099,6 +2099,14 @@
"id": "cli.license.critical",
"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",
"translation": "Unable to decode image."

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

@@ -61,6 +61,7 @@ var flagCmdPermanentDeleteTeam bool
var flagCmdPermanentDeleteAllUsers bool
var flagCmdResetDatabase bool
var flagCmdRunLdapSync bool
var flagCmdMigrateAccounts bool
var flagUsername string
var flagCmdUploadLicense bool
var flagConfigFile string
@@ -73,6 +74,9 @@ var flagSiteURL string
var flagConfirmBackup string
var flagRole string
var flagRunCmds bool
var flagFromAuth string
var flagToAuth string
var flagMatchField string
func doLoadConfig(filename string) (err string) {
defer func() {
@@ -288,6 +292,9 @@ func parseCmds() {
flag.StringVar(&flagChannelName, "channel_name", "", "")
flag.StringVar(&flagSiteURL, "site_url", "", "")
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.BoolVar(&flagCmdUpdateDb30, "upgrade_db_30", false, "")
@@ -311,6 +318,7 @@ func parseCmds() {
flag.BoolVar(&flagCmdPermanentDeleteAllUsers, "permanent_delete_all_users", false, "")
flag.BoolVar(&flagCmdResetDatabase, "reset_database", false, "")
flag.BoolVar(&flagCmdRunLdapSync, "ldap_sync", false, "")
flag.BoolVar(&flagCmdMigrateAccounts, "migrate_accounts", false, "")
flag.BoolVar(&flagCmdUploadLicense, "upload_license", false, "")
flag.Parse()
@@ -335,6 +343,7 @@ func parseCmds() {
flagCmdPermanentDeleteAllUsers ||
flagCmdResetDatabase ||
flagCmdRunLdapSync ||
flagCmdMigrateAccounts ||
flagCmdUploadLicense)
}
@@ -359,6 +368,7 @@ func runCmds() {
cmdResetDatabase()
cmdUploadLicense()
cmdRunLdapSync()
cmdRunMigrateAccounts()
}
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() {
if flagCmdUploadLicense {
if model.BuildEnterpriseReady != "true" {
@@ -1651,6 +1699,11 @@ COMMANDS:
Example:
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
http://www.mattermost.org/upgrading-to-mattermost-3-0/

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

@@ -84,6 +84,12 @@ func (task *ScheduledTask) Cancel() {
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 {
return fmt.Sprintf(
"%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")
}
}