Commit 342d05bc authored by Jesús Espino's avatar Jesús Espino Committed by GitHub

Adding saml migration command (#8263)

* Adding saml migration command

* Texts fixed
parent 75d9a3a3
......@@ -3,9 +3,12 @@
package main
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
l4g "github.com/alecthomas/log4go"
"github.com/mattermost/mattermost-server/app"
"github.com/mattermost/mattermost-server/model"
"github.com/spf13/cobra"
......@@ -87,25 +90,41 @@ var deleteAllUsersCmd = &cobra.Command{
}
var migrateAuthCmd = &cobra.Command{
Use: "migrate_auth [from_auth] [to_auth] [match_field]",
Short: "Mass migrate user accounts authentication type",
Long: `Migrates accounts from one authentication provider to another. For example, you can upgrade your authentication provider from email to ldap.
Use: "migrate_auth [from_auth] [to_auth] [migration-options]",
Short: "Mass migrate user accounts authentication type",
Long: `Migrates accounts from one authentication provider to another. For example, you can upgrade your authentication provider from email to ldap.`,
Example: " user migrate_auth email saml users.json",
Args: func(cmd *cobra.Command, args []string) error {
if len(args) < 2 {
return errors.New("Auth migration requires at least 2 arguments.")
}
from_auth:
The authentication service to migrate users accounts from.
Supported options: email, gitlab, saml.
toAuth := args[1]
to_auth:
The authentication service to migrate users to.
Supported options: ldap.
if toAuth != "ldap" && toAuth != "saml" {
return errors.New("Invalid to_auth parameter, must be saml or ldap.")
}
match_field:
The field that is guaranteed to be the same in both authentication services. For example, if the users emails are consistent set to email.
Supported options: email, username.
if toAuth == "ldap" && len(args) != 3 {
return errors.New("Ldap migration requires 3 arguments.")
}
Will display any accounts that are not migrated successfully.`,
Example: " user migrate_auth email ladp email",
RunE: migrateAuthCmdF,
autoFlag, _ := cmd.Flags().GetBool("auto")
if toAuth == "saml" && autoFlag {
if len(args) != 2 {
return errors.New("Saml migration requires two arguments when using the --auto flag. See help text for details.")
}
}
if toAuth == "saml" && !autoFlag {
if len(args) != 3 {
return errors.New("Saml migration requires three arguments when not using the --auto flag. See help text for details.")
}
}
return nil
},
RunE: migrateAuthCmdF,
}
var verifyUserCmd = &cobra.Command{
......@@ -138,7 +157,69 @@ func init() {
deleteAllUsersCmd.Flags().Bool("confirm", false, "Confirm you really want to delete the user and a DB backup has been performed.")
migrateAuthCmd.Flags().Bool("force", false, "Force the migration to occour even if there are duplicates on the LDAP server. Duplicates will not be migrated.")
migrateAuthCmd.Flags().Bool("force", false, "Force the migration to occur even if there are duplicates on the LDAP server. Duplicates will not be migrated. (ldap only)")
migrateAuthCmd.Flags().Bool("auto", false, "Automatically migrate all users. Assumes the usernames and emails are identical between Mattermost and SAML services. (saml only)")
migrateAuthCmd.Flags().Bool("dryRun", false, "Run a simulation of the migration process without changing the database.")
migrateAuthCmd.SetUsageTemplate(`Usage:
platform user migrate_auth [from_auth] [to_auth] [migration-options] [flags]
Examples:
{{.Example}}
Arguments:
from_auth:
The authentication service to migrate users accounts from.
Supported options: email, gitlab, ldap, saml.
to_auth:
The authentication service to migrate users to.
Supported options: ldap, saml.
migration-options:
Migration specific options, full command help for more information.
Flags:
{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}
Global Flags:
{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}
`)
migrateAuthCmd.SetHelpTemplate(`Usage:
platform user migrate_auth [from_auth] [to_auth] [migration-options] [flags]
Examples:
{{.Example}}
Arguments:
from_auth:
The authentication service to migrate users accounts from.
Supported options: email, gitlab, ldap, saml.
to_auth:
The authentication service to migrate users to.
Supported options: ldap, saml.
migration-options (ldap):
match_field:
The field that is guaranteed to be the same in both authentication services. For example, if the users emails are consistent set to email.
Supported options: email, username.
migration-options (saml):
users_file:
The path of a json file with the usernames and emails of all users to migrate to SAML. The username and email must be the same that the SAML service provider store. And the email must match with the email in mattermost database.
Example json content:
{
"usr1@email.com": "usr.one",
"usr2@email.com": "usr.two"
}
Flags:
{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}
Global Flags:
{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}
`)
userCmd.AddCommand(
userActivateCmd,
......@@ -416,27 +497,25 @@ func deleteAllUsersCommandF(cmd *cobra.Command, args []string) error {
}
func migrateAuthCmdF(cmd *cobra.Command, args []string) error {
if args[1] == "saml" {
return migrateAuthToSamlCmdF(cmd, args)
}
return migrateAuthToLdapCmdF(cmd, args)
}
func migrateAuthToLdapCmdF(cmd *cobra.Command, args []string) error {
a, err := initDBCommandContextCobra(cmd)
if err != nil {
return err
}
if len(args) != 3 {
return errors.New("Expected three arguments. See help text for details.")
}
fromAuth := args[0]
toAuth := args[1]
matchField := args[2]
matchField := args[1]
if len(fromAuth) == 0 || (fromAuth != "email" && fromAuth != "gitlab" && fromAuth != "saml") {
return errors.New("Invalid from_auth argument")
}
if len(toAuth) == 0 || toAuth != "ldap" {
return errors.New("Invalid to_auth argument")
}
// Email auth in Mattermost system is represented by ""
if fromAuth == "email" {
fromAuth = ""
......@@ -447,9 +526,10 @@ func migrateAuthCmdF(cmd *cobra.Command, args []string) error {
}
forceFlag, _ := cmd.Flags().GetBool("force")
dryRunFlag, _ := cmd.Flags().GetBool("dryRun")
if migrate := a.AccountMigration; migrate != nil {
if err := migrate.MigrateToLdap(fromAuth, matchField, forceFlag); err != nil {
if err := migrate.MigrateToLdap(fromAuth, matchField, forceFlag, dryRunFlag); err != nil {
return errors.New("Error while migrating users: " + err.Error())
}
......@@ -459,6 +539,61 @@ func migrateAuthCmdF(cmd *cobra.Command, args []string) error {
return nil
}
func migrateAuthToSamlCmdF(cmd *cobra.Command, args []string) error {
a, err := initDBCommandContextCobra(cmd)
if err != nil {
return err
}
dryRunFlag, _ := cmd.Flags().GetBool("dryRun")
autoFlag, _ := cmd.Flags().GetBool("auto")
matchesFile := ""
matches := map[string]string{}
if !autoFlag {
matchesFile = args[1]
file, e := ioutil.ReadFile(matchesFile)
if e != nil {
return errors.New("Invalid users file.")
}
if json.Unmarshal(file, &matches) != nil {
return errors.New("Invalid users file.")
}
}
fromAuth := args[0]
if len(fromAuth) == 0 || (fromAuth != "email" && fromAuth != "gitlab" && fromAuth != "ldap") {
return errors.New("Invalid from_auth argument")
}
if autoFlag && !dryRunFlag {
var confirm string
CommandPrettyPrintln("You are about to perform an automatic \"" + fromAuth + " to saml\" migration. This must only be done if your current Mattermost users with " + fromAuth + " auth have the same username and email in your SAML service. Otherwise, provide the usernames and emails from your SAML Service using the \"users file\" without the \"--auto\" option.\n\nDo you want to proceed with automatic migration anyway? (YES/NO):")
fmt.Scanln(&confirm)
if confirm != "YES" {
return errors.New("ABORTED: You did not answer YES exactly, in all capitals.")
}
}
// Email auth in Mattermost system is represented by ""
if fromAuth == "email" {
fromAuth = ""
}
if migrate := a.AccountMigration; migrate != nil {
if err := migrate.MigrateToSaml(fromAuth, matches, autoFlag, dryRunFlag); err != nil {
return errors.New("Error while migrating users: " + err.Error())
}
l4g.Close()
CommandPrettyPrintln("Sucessfully migrated accounts.")
}
return nil
}
func verifyUserCmdF(cmd *cobra.Command, args []string) error {
a, err := initDBCommandContextCobra(cmd)
if err != nil {
......
......@@ -6,5 +6,6 @@ package einterfaces
import "github.com/mattermost/mattermost-server/model"
type AccountMigrationInterface interface {
MigrateToLdap(fromAuthService string, forignUserFieldNameToMatch string, force bool) *model.AppError
MigrateToLdap(fromAuthService string, forignUserFieldNameToMatch string, force bool, dryRun bool) *model.AppError
MigrateToSaml(fromAuthService string, usersMap map[string]string, auto bool, dryRun bool) *model.AppError
}
......@@ -4186,6 +4186,18 @@
"id": "ent.migration.migratetoldap.user_not_found",
"translation": "Unable to find user on AD/LDAP server: "
},
{
"id": "ent.migration.migratetosaml.user_not_found_in_users_mapping_file",
"translation": "User not found in the users file."
},
{
"id": "ent.migration.migratetosaml.username_already_used_by_other_user",
"translation": "Username already used by another Mattermost user."
},
{
"id": "ent.migration.migratetosaml.email_already_used_by_other_user",
"translation": "Email already used by another SAML user."
},
{
"id": "ent.saml.attribute.app_error",
"translation": "SAML login was unsuccessful because one of the attributes is incorrect. Please contact your System Administrator."
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment