github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/cmd/mattermost/commands/user.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package commands 5 6 import ( 7 "encoding/json" 8 "errors" 9 "fmt" 10 "io/ioutil" 11 "strings" 12 13 "github.com/mattermost/mattermost-server/v5/app" 14 "github.com/mattermost/mattermost-server/v5/audit" 15 "github.com/mattermost/mattermost-server/v5/model" 16 "github.com/spf13/cobra" 17 ) 18 19 var UserCmd = &cobra.Command{ 20 Use: "user", 21 Short: "Management of users", 22 } 23 24 var UserActivateCmd = &cobra.Command{ 25 Use: "activate [emails, usernames, userIds]", 26 Short: "Activate users", 27 Long: "Activate users that have been deactivated.", 28 Example: ` user activate user@example.com 29 user activate username`, 30 RunE: userActivateCmdF, 31 } 32 33 var UserDeactivateCmd = &cobra.Command{ 34 Use: "deactivate [emails, usernames, userIds]", 35 Short: "Deactivate users", 36 Long: "Deactivate users. Deactivated users are immediately logged out of all sessions and are unable to log back in.", 37 Example: ` user deactivate user@example.com 38 user deactivate username`, 39 RunE: userDeactivateCmdF, 40 } 41 42 var UserCreateCmd = &cobra.Command{ 43 Use: "create", 44 Short: "Create a user", 45 Long: "Create a user", 46 Example: ` user create --email user@example.com --username userexample --password Password1`, 47 RunE: userCreateCmdF, 48 } 49 50 var UserConvertCmd = &cobra.Command{ 51 Use: "convert [emails, usernames, userIds] --bot", 52 Short: "Convert users to bots, or a bot to a user", 53 Long: "Convert users to bots, or a bot to a user", 54 Example: ` user convert user@example.com anotherUser --bot 55 user convert botusername --email new.email@email.com --password password --user`, 56 Args: cobra.MinimumNArgs(1), 57 RunE: userConvertCmdF, 58 } 59 60 var UserInviteCmd = &cobra.Command{ 61 Use: "invite [email] [teams]", 62 Short: "Send user an email invite to a team.", 63 Long: `Send user an email invite to a team. 64 You can invite a user to multiple teams by listing them. 65 You can specify teams by name or ID.`, 66 Example: ` user invite user@example.com myteam 67 user invite user@example.com myteam1 myteam2`, 68 RunE: userInviteCmdF, 69 } 70 71 var ResetUserPasswordCmd = &cobra.Command{ 72 Use: "password [user] [password]", 73 Short: "Set a user's password", 74 Long: "Set a user's password", 75 Example: " user password user@example.com Password1", 76 RunE: resetUserPasswordCmdF, 77 } 78 79 var updateUserEmailCmd = &cobra.Command{ 80 Use: "email [user] [new email]", 81 Short: "Change email of the user", 82 Long: "Change email of the user.", 83 Example: " user email testuser user@example.com", 84 RunE: updateUserEmailCmdF, 85 } 86 87 var ResetUserMfaCmd = &cobra.Command{ 88 Use: "resetmfa [users]", 89 Short: "Turn off MFA", 90 Long: `Turn off multi-factor authentication for a user. 91 If MFA enforcement is enabled, the user will be forced to re-enable MFA as soon as they login.`, 92 Example: " user resetmfa user@example.com", 93 RunE: resetUserMfaCmdF, 94 } 95 96 var DeleteUserCmd = &cobra.Command{ 97 Use: "delete [users]", 98 Short: "Delete users and all posts", 99 Long: "Permanently delete user and all related information including posts.", 100 Example: " user delete user@example.com", 101 RunE: deleteUserCmdF, 102 } 103 104 var DeleteAllUsersCmd = &cobra.Command{ 105 Use: "deleteall", 106 Short: "Delete all users and all posts", 107 Long: "Permanently delete all users and all related information including posts.", 108 Example: " user deleteall", 109 RunE: deleteAllUsersCommandF, 110 } 111 112 var MigrateAuthCmd = &cobra.Command{ 113 Use: "migrate_auth [from_auth] [to_auth] [migration-options]", 114 Short: "Mass migrate user accounts authentication type", 115 Long: `Migrates accounts from one authentication provider to another. For example, you can upgrade your authentication provider from email to ldap.`, 116 Example: " user migrate_auth email saml users.json", 117 Args: func(command *cobra.Command, args []string) error { 118 if len(args) < 2 { 119 return errors.New("Auth migration requires at least 2 arguments.") 120 } 121 122 toAuth := args[1] 123 124 if toAuth != "ldap" && toAuth != "saml" { 125 return errors.New("Invalid to_auth parameter, must be saml or ldap.") 126 } 127 128 if toAuth == "ldap" && len(args) != 3 { 129 return errors.New("Ldap migration requires 3 arguments.") 130 } 131 132 autoFlag, _ := command.Flags().GetBool("auto") 133 134 if toAuth == "saml" && autoFlag { 135 if len(args) != 2 { 136 return errors.New("Saml migration requires two arguments when using the --auto flag. See help text for details.") 137 } 138 } 139 140 if toAuth == "saml" && !autoFlag { 141 if len(args) != 3 { 142 return errors.New("Saml migration requires three arguments when not using the --auto flag. See help text for details.") 143 } 144 } 145 return nil 146 }, 147 RunE: migrateAuthCmdF, 148 } 149 150 var VerifyUserCmd = &cobra.Command{ 151 Use: "verify [users]", 152 Short: "Verify email of users", 153 Long: "Verify the emails of some users.", 154 Example: " user verify user1", 155 RunE: verifyUserCmdF, 156 } 157 158 var SearchUserCmd = &cobra.Command{ 159 Use: "search [users]", 160 Short: "Search for users", 161 Long: "Search for users based on username, email, or user ID.", 162 Example: " user search user1@mail.com user2@mail.com", 163 RunE: searchUserCmdF, 164 } 165 166 func init() { 167 UserCreateCmd.Flags().String("username", "", "Required. Username for the new user account.") 168 UserCreateCmd.Flags().String("email", "", "Required. The email address for the new user account.") 169 UserCreateCmd.Flags().String("password", "", "Required. The password for the new user account.") 170 UserCreateCmd.Flags().String("nickname", "", "Optional. The nickname for the new user account.") 171 UserCreateCmd.Flags().String("firstname", "", "Optional. The first name for the new user account.") 172 UserCreateCmd.Flags().String("lastname", "", "Optional. The last name for the new user account.") 173 UserCreateCmd.Flags().String("locale", "", "Optional. The locale (ex: en, fr) for the new user account.") 174 UserCreateCmd.Flags().Bool("system_admin", false, "Optional. If supplied, the new user will be a system administrator. Defaults to false.") 175 176 UserConvertCmd.Flags().Bool("bot", false, "If supplied, convert users to bots.") 177 UserConvertCmd.Flags().Bool("user", false, "If supplied, convert a bot to a user.") 178 UserConvertCmd.Flags().String("password", "", "The password for converted new user account. Required when \"user\" flag is set.") 179 UserConvertCmd.Flags().String("username", "", "Username for the converted user account. Ignored when \"user\" flag is missing.") 180 UserConvertCmd.Flags().String("email", "", "The email address for the converted user account. Ignored when \"user\" flag is missing.") 181 UserConvertCmd.Flags().String("nickname", "", "The nickname for the converted user account. Ignored when \"user\" flag is missing.") 182 UserConvertCmd.Flags().String("firstname", "", "The first name for the converted user account. Ignored when \"user\" flag is missing.") 183 UserConvertCmd.Flags().String("lastname", "", "The last name for the converted user account. Ignored when \"user\" flag is missing.") 184 UserConvertCmd.Flags().String("locale", "", "The locale (ex: en, fr) for converted new user account. Ignored when \"user\" flag is missing.") 185 UserConvertCmd.Flags().Bool("system_admin", false, "If supplied, the converted user will be a system administrator. Defaults to false. Ignored when \"user\" flag is missing.") 186 187 DeleteUserCmd.Flags().Bool("confirm", false, "Confirm you really want to delete the user and a DB backup has been performed.") 188 189 DeleteAllUsersCmd.Flags().Bool("confirm", false, "Confirm you really want to delete the user and a DB backup has been performed.") 190 191 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)") 192 MigrateAuthCmd.Flags().Bool("auto", false, "Automatically migrate all users. Assumes the usernames and emails are identical between Mattermost and SAML services. (saml only)") 193 MigrateAuthCmd.Flags().Bool("dryRun", false, "Run a simulation of the migration process without changing the database.") 194 MigrateAuthCmd.SetUsageTemplate(`Usage: 195 mattermost user migrate_auth [from_auth] [to_auth] [migration-options] [flags] 196 197 Examples: 198 {{.Example}} 199 200 Arguments: 201 from_auth: 202 The authentication service to migrate users accounts from. 203 Supported options: email, gitlab, ldap, saml. 204 205 to_auth: 206 The authentication service to migrate users to. 207 Supported options: ldap, saml. 208 209 migration-options: 210 Migration specific options, full command help for more information. 211 212 Flags: 213 {{.LocalFlags.FlagUsages | trimTrailingWhitespaces}} 214 215 Global Flags: 216 {{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}} 217 `) 218 MigrateAuthCmd.SetHelpTemplate(`Usage: 219 mattermost user migrate_auth [from_auth] [to_auth] [migration-options] [flags] 220 221 Examples: 222 {{.Example}} 223 224 Arguments: 225 from_auth: 226 The authentication service to migrate users accounts from. 227 Supported options: email, gitlab, ldap, saml. 228 229 to_auth: 230 The authentication service to migrate users to. 231 Supported options: ldap, saml. 232 233 migration-options (ldap): 234 match_field: 235 The field that is guaranteed to be the same in both authentication services. For example, if the users emails are consistent set to email. 236 Supported options: email, username. 237 238 migration-options (saml): 239 users_file: 240 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. 241 242 Example json content: 243 { 244 "usr1@email.com": "usr.one", 245 "usr2@email.com": "usr.two" 246 } 247 248 Flags: 249 {{.LocalFlags.FlagUsages | trimTrailingWhitespaces}} 250 251 Global Flags: 252 {{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}} 253 `) 254 255 UserCmd.AddCommand( 256 UserActivateCmd, 257 UserDeactivateCmd, 258 UserCreateCmd, 259 UserConvertCmd, 260 UserInviteCmd, 261 ResetUserPasswordCmd, 262 updateUserEmailCmd, 263 ResetUserMfaCmd, 264 DeleteUserCmd, 265 DeleteAllUsersCmd, 266 MigrateAuthCmd, 267 VerifyUserCmd, 268 SearchUserCmd, 269 ) 270 RootCmd.AddCommand(UserCmd) 271 } 272 273 func userActivateCmdF(command *cobra.Command, args []string) error { 274 a, err := InitDBCommandContextCobra(command) 275 if err != nil { 276 return err 277 } 278 defer a.Srv().Shutdown() 279 280 if len(args) < 1 { 281 return errors.New("Expected at least one argument. See help text for details.") 282 } 283 284 changeUsersActiveStatus(a, args, true) 285 286 return nil 287 } 288 289 func changeUsersActiveStatus(a *app.App, userArgs []string, active bool) { 290 users := getUsersFromUserArgs(a, userArgs) 291 for i, user := range users { 292 err := changeUserActiveStatus(a, user, userArgs[i], active) 293 294 if err != nil { 295 CommandPrintErrorln(err.Error()) 296 } 297 } 298 } 299 300 func changeUserActiveStatus(a *app.App, user *model.User, userArg string, activate bool) error { 301 if user == nil { 302 return fmt.Errorf("Can't find user '%v'", userArg) 303 } 304 if user.IsSSOUser() { 305 fmt.Println("You must also deactivate this user in the SSO provider or they will be reactivated on next login or sync.") 306 } 307 updatedUser, err := a.UpdateActive(user, activate) 308 if err != nil { 309 return fmt.Errorf("Unable to change activation status of user: %v", userArg) 310 } 311 312 auditRec := a.MakeAuditRecord("changeActiveUserStatus", audit.Success) 313 auditRec.AddMeta("user", updatedUser) 314 auditRec.AddMeta("activate", activate) 315 a.LogAuditRec(auditRec, nil) 316 317 return nil 318 } 319 320 func userDeactivateCmdF(command *cobra.Command, args []string) error { 321 a, err := InitDBCommandContextCobra(command) 322 if err != nil { 323 return err 324 } 325 defer a.Srv().Shutdown() 326 327 if len(args) < 1 { 328 return errors.New("Expected at least one argument. See help text for details.") 329 } 330 331 changeUsersActiveStatus(a, args, false) 332 333 return nil 334 } 335 336 func userCreateCmdF(command *cobra.Command, args []string) error { 337 a, err := InitDBCommandContextCobra(command) 338 if err != nil { 339 return err 340 } 341 defer a.Srv().Shutdown() 342 343 username, erru := command.Flags().GetString("username") 344 if erru != nil || username == "" { 345 return errors.New("Username is required") 346 } 347 email, erre := command.Flags().GetString("email") 348 if erre != nil || email == "" { 349 return errors.New("Email is required") 350 } 351 email = strings.ToLower((email)) 352 password, errp := command.Flags().GetString("password") 353 if errp != nil || password == "" { 354 return errors.New("Password is required") 355 } 356 nickname, _ := command.Flags().GetString("nickname") 357 firstname, _ := command.Flags().GetString("firstname") 358 lastname, _ := command.Flags().GetString("lastname") 359 locale, _ := command.Flags().GetString("locale") 360 systemAdmin, _ := command.Flags().GetBool("system_admin") 361 362 user := &model.User{ 363 Username: username, 364 Email: email, 365 Password: password, 366 Nickname: nickname, 367 FirstName: firstname, 368 LastName: lastname, 369 Locale: locale, 370 } 371 372 ruser, err := a.CreateUser(user) 373 if ruser == nil { 374 return errors.New("Unable to create user. Error: " + err.Error()) 375 } 376 377 if systemAdmin { 378 if _, err := a.UpdateUserRoles(ruser.Id, "system_user system_admin", false); err != nil { 379 return errors.New("Unable to make user system admin. Error: " + err.Error()) 380 } 381 } else { 382 // This else case exists to prevent the first user created from being 383 // created as a system admin unless explicitly specified. 384 if _, err := a.UpdateUserRoles(ruser.Id, "system_user", false); err != nil { 385 return errors.New("If this is the first user: Unable to prevent user from being system admin. Error: " + err.Error()) 386 } 387 } 388 389 CommandPrettyPrintln("id: " + ruser.Id) 390 CommandPrettyPrintln("username: " + ruser.Username) 391 CommandPrettyPrintln("nickname: " + ruser.Nickname) 392 CommandPrettyPrintln("position: " + ruser.Position) 393 CommandPrettyPrintln("first_name: " + ruser.FirstName) 394 CommandPrettyPrintln("last_name: " + ruser.LastName) 395 CommandPrettyPrintln("email: " + ruser.Email) 396 CommandPrettyPrintln("auth_service: " + ruser.AuthService) 397 398 auditRec := a.MakeAuditRecord("userCreate", audit.Success) 399 auditRec.AddMeta("user", ruser) 400 auditRec.AddMeta("system_admin", systemAdmin) 401 a.LogAuditRec(auditRec, nil) 402 403 return nil 404 } 405 406 func usersToBots(args []string, a *app.App) { 407 users := getUsersFromUserArgs(a, args) 408 for i, user := range users { 409 if user == nil { 410 CommandPrintErrorln(fmt.Errorf("Unable to find user \"%s\"", args[i])) 411 continue 412 } 413 414 bot, err := a.ConvertUserToBot(user) 415 if err != nil { 416 CommandPrintErrorln(err.Error()) 417 continue 418 } 419 420 CommandPrettyPrintln(fmt.Sprintf("User %s is converted to bot successfully", bot.UserId)) 421 422 auditRec := a.MakeAuditRecord("userToBot", audit.Success) 423 auditRec.AddMeta("user", user) 424 a.LogAuditRec(auditRec, nil) 425 } 426 } 427 428 func getUpdatedPassword(command *cobra.Command, a *app.App, user *model.User) (string, error) { 429 password, err := command.Flags().GetString("password") 430 if err != nil { 431 return "", fmt.Errorf("Unable to read password. Error: %s", err.Error()) 432 } 433 434 if password == "" { 435 return "", errors.New("Password is required.") 436 } 437 438 return password, nil 439 } 440 441 func getUpdatedUserModel(command *cobra.Command, a *app.App, user *model.User) (*model.User, error) { 442 username, _ := command.Flags().GetString("username") 443 if username == "" { 444 if user.Username == "" { 445 return nil, errors.New("Invalid username. Username is empty.") 446 } 447 } else { 448 user.Username = username 449 } 450 451 email, _ := command.Flags().GetString("email") 452 if email == "" { 453 if user.Email == "" { 454 return nil, errors.New("Invalid email. Email is empty.") 455 } 456 } else { 457 user.Email = email 458 } 459 460 nickname, _ := command.Flags().GetString("nickname") 461 if nickname != "" { 462 user.Nickname = nickname 463 } 464 465 firstname, _ := command.Flags().GetString("firstname") 466 if firstname != "" { 467 user.FirstName = firstname 468 } 469 470 lastname, _ := command.Flags().GetString("lastname") 471 if lastname != "" { 472 user.LastName = lastname 473 } 474 475 locale, _ := command.Flags().GetString("locale") 476 if locale != "" { 477 user.Locale = locale 478 } 479 480 if !user.IsLDAPUser() && !user.IsSAMLUser() && !app.CheckUserDomain(user, *a.Config().TeamSettings.RestrictCreationToDomains) { 481 return nil, errors.New("The email does not belong to an accepted domain.") 482 } 483 484 return user, nil 485 } 486 487 func botToUser(command *cobra.Command, args []string, a *app.App) error { 488 if len(args) != 1 { 489 return errors.New("Expect 1 argument. See help text for more details.") 490 } 491 492 user := getUserFromUserArg(a, args[0]) 493 if user == nil { 494 return errors.New("Unable to find bot.") 495 } 496 497 _, appErr := a.GetBot(user.Id, false) 498 if appErr != nil { 499 return fmt.Errorf("Unable to find bot. Error: %s", appErr.Error()) 500 } 501 502 password, err := getUpdatedPassword(command, a, user) 503 if err != nil { 504 return err 505 } 506 507 user, err = getUpdatedUserModel(command, a, user) 508 if err != nil { 509 return err 510 } 511 512 user, appErr = a.UpdateUser(user, false) 513 if appErr != nil { 514 return fmt.Errorf("Unable to update user. Error: %s" + appErr.Error()) 515 } 516 517 appErr = a.UpdatePassword(user, password) 518 if appErr != nil { 519 return fmt.Errorf("Unable to update password. Error: %s", appErr.Error()) 520 } 521 522 systemAdmin, _ := command.Flags().GetBool("system_admin") 523 if systemAdmin && !user.IsInRole(model.SYSTEM_ADMIN_ROLE_ID) { 524 if _, appErr = a.UpdateUserRoles( 525 user.Id, 526 fmt.Sprintf("%s %s", user.Roles, model.SYSTEM_ADMIN_ROLE_ID), 527 false); appErr != nil { 528 return fmt.Errorf("Unable to make user system admin. Error: %s" + appErr.Error()) 529 } 530 } 531 532 err = a.Srv().Store.Bot().PermanentDelete(user.Id) 533 if err != nil { 534 return fmt.Errorf("Unable to delete bot. Error: %v", err) 535 } 536 537 CommandPrettyPrintln("id: " + user.Id) 538 CommandPrettyPrintln("username: " + user.Username) 539 CommandPrettyPrintln("email: " + user.Email) 540 CommandPrettyPrintln("nickname: " + user.Nickname) 541 CommandPrettyPrintln("first_name: " + user.FirstName) 542 CommandPrettyPrintln("last_name: " + user.LastName) 543 CommandPrettyPrintln("roles: " + user.Roles) 544 CommandPrettyPrintln("locale: " + user.Locale) 545 546 auditRec := a.MakeAuditRecord("botToUser", audit.Success) 547 auditRec.AddMeta("bot", user) 548 auditRec.AddMeta("user", user) 549 a.LogAuditRec(auditRec, nil) 550 551 return nil 552 } 553 554 func userConvertCmdF(command *cobra.Command, args []string) error { 555 a, err := InitDBCommandContextCobra(command) 556 if err != nil { 557 return err 558 } 559 defer a.Srv().Shutdown() 560 561 toBot, err := command.Flags().GetBool("bot") 562 if err != nil { 563 return errors.New("Invalid command. See help text for details.") 564 } 565 566 toUser, err := command.Flags().GetBool("user") 567 if err != nil { 568 return errors.New("Invalid command. See help text for details.") 569 } 570 571 if !(toUser || toBot) { 572 return errors.New("Expect either \"user\" flag or \"bot\" flag. See help text for details.") 573 } 574 575 if toUser && toBot { 576 return errors.New("Expect either \"user\" flag or \"bot\" flag but not both. See help text for details.") 577 } 578 579 if toUser { 580 return botToUser(command, args, a) 581 } 582 583 usersToBots(args, a) 584 return nil 585 } 586 587 func userInviteCmdF(command *cobra.Command, args []string) error { 588 a, err := InitDBCommandContextCobra(command) 589 if err != nil { 590 return err 591 } 592 defer a.Srv().Shutdown() 593 594 if len(args) < 2 { 595 return errors.New("Expected at least two arguments. See help text for details.") 596 } 597 598 email := args[0] 599 email = strings.ToLower(email) 600 if !model.IsValidEmail(email) { 601 return errors.New("Invalid email") 602 } 603 604 teams := getTeamsFromTeamArgs(a, args[1:]) 605 for i, team := range teams { 606 err := inviteUser(a, email, team, args[i+1]) 607 608 if err != nil { 609 CommandPrintErrorln(err.Error()) 610 } 611 } 612 613 return nil 614 } 615 616 func inviteUser(a *app.App, email string, team *model.Team, teamArg string) error { 617 invites := []string{email} 618 if team == nil { 619 return fmt.Errorf("Can't find team '%v'", teamArg) 620 } 621 622 if !*a.Config().ServiceSettings.EnableEmailInvitations { 623 return fmt.Errorf("Email invites are disabled.") 624 } 625 626 a.Srv().EmailService.SendInviteEmails(team, "Administrator", "Mattermost CLI "+model.NewId(), invites, *a.Config().ServiceSettings.SiteURL) 627 CommandPrettyPrintln("Invites may or may not have been sent.") 628 629 auditRec := a.MakeAuditRecord("inviteUser", audit.Success) 630 auditRec.AddMeta("email", email) 631 auditRec.AddMeta("team", team) 632 a.LogAuditRec(auditRec, nil) 633 634 return nil 635 } 636 637 func resetUserPasswordCmdF(command *cobra.Command, args []string) error { 638 a, err := InitDBCommandContextCobra(command) 639 if err != nil { 640 return err 641 } 642 defer a.Srv().Shutdown() 643 644 if len(args) != 2 { 645 return errors.New("Expected two arguments. See help text for details.") 646 } 647 648 user := getUserFromUserArg(a, args[0]) 649 if user == nil { 650 return errors.New("Unable to find user '" + args[0] + "'") 651 } 652 password := args[1] 653 654 if err := a.Srv().Store.User().UpdatePassword(user.Id, model.HashPassword(password)); err != nil { 655 return err 656 } 657 658 auditRec := a.MakeAuditRecord("resetUserPassword", audit.Success) 659 auditRec.AddMeta("user", user) 660 a.LogAuditRec(auditRec, nil) 661 662 return nil 663 } 664 665 func updateUserEmailCmdF(command *cobra.Command, args []string) error { 666 a, err := InitDBCommandContextCobra(command) 667 if err != nil { 668 return err 669 } 670 defer a.Srv().Shutdown() 671 672 if len(args) != 2 { 673 return errors.New("Expected two arguments. See help text for details.") 674 } 675 676 newEmail := args[1] 677 newEmail = strings.ToLower(newEmail) 678 if !model.IsValidEmail(newEmail) { 679 return errors.New("Invalid email: '" + newEmail + "'") 680 } 681 682 if len(args) != 2 { 683 return errors.New("Expected two arguments. See help text for details.") 684 } 685 686 user := getUserFromUserArg(a, args[0]) 687 if user == nil { 688 return errors.New("Unable to find user '" + args[0] + "'") 689 } 690 691 user.Email = newEmail 692 _, errUpdate := a.UpdateUser(user, true) 693 if errUpdate != nil { 694 return errors.New(errUpdate.Message) 695 } 696 697 auditRec := a.MakeAuditRecord("updateUserEmail", audit.Success) 698 auditRec.AddMeta("user", user) 699 auditRec.AddMeta("email", newEmail) 700 a.LogAuditRec(auditRec, nil) 701 702 return nil 703 } 704 705 func resetUserMfaCmdF(command *cobra.Command, args []string) error { 706 a, err := InitDBCommandContextCobra(command) 707 if err != nil { 708 return err 709 } 710 defer a.Srv().Shutdown() 711 712 if len(args) < 1 { 713 return errors.New("Expected at least one argument. See help text for details.") 714 } 715 716 users := getUsersFromUserArgs(a, args) 717 for i, user := range users { 718 if user == nil { 719 return errors.New("Unable to find user '" + args[i] + "'") 720 } 721 722 if err := a.DeactivateMfa(user.Id); err != nil { 723 return err 724 } 725 726 auditRec := a.MakeAuditRecord("resetUserMfa", audit.Success) 727 auditRec.AddMeta("user", user) 728 a.LogAuditRec(auditRec, nil) 729 } 730 731 return nil 732 } 733 734 func deleteUserCmdF(command *cobra.Command, args []string) error { 735 a, err := InitDBCommandContextCobra(command) 736 if err != nil { 737 return err 738 } 739 defer a.Srv().Shutdown() 740 741 if len(args) < 1 { 742 return errors.New("Expected at least one argument. See help text for details.") 743 } 744 745 confirmFlag, _ := command.Flags().GetBool("confirm") 746 if !confirmFlag { 747 var confirm string 748 CommandPrettyPrintln("Have you performed a database backup? (YES/NO): ") 749 fmt.Scanln(&confirm) 750 751 if confirm != "YES" { 752 return errors.New("ABORTED: You did not answer YES exactly, in all capitals.") 753 } 754 CommandPrettyPrintln("Are you sure you want to permanently delete the specified users? (YES/NO): ") 755 fmt.Scanln(&confirm) 756 if confirm != "YES" { 757 return errors.New("ABORTED: You did not answer YES exactly, in all capitals.") 758 } 759 } 760 761 users := getUsersFromUserArgs(a, args) 762 763 for i, user := range users { 764 if user == nil { 765 return errors.New("Unable to find user '" + args[i] + "'") 766 } 767 768 if user.IsBot { 769 if err := a.PermanentDeleteBot(user.Id); err != nil { 770 return err 771 } 772 } else { 773 if err := a.PermanentDeleteUser(user); err != nil { 774 return err 775 } 776 } 777 778 auditRec := a.MakeAuditRecord("deleteUser", audit.Success) 779 auditRec.AddMeta("user", user) 780 auditRec.AddMeta("isBot", user.IsBot) 781 a.LogAuditRec(auditRec, nil) 782 } 783 784 return nil 785 } 786 787 func deleteAllUsersCommandF(command *cobra.Command, args []string) error { 788 a, err := InitDBCommandContextCobra(command) 789 if err != nil { 790 return err 791 } 792 defer a.Srv().Shutdown() 793 794 if len(args) > 0 { 795 return errors.New("Expected zero arguments.") 796 } 797 798 confirmFlag, _ := command.Flags().GetBool("confirm") 799 if !confirmFlag { 800 var confirm string 801 CommandPrettyPrintln("Have you performed a database backup? (YES/NO): ") 802 fmt.Scanln(&confirm) 803 804 if confirm != "YES" { 805 return errors.New("ABORTED: You did not answer YES exactly, in all capitals.") 806 } 807 CommandPrettyPrintln("Are you sure you want to permanently delete all user accounts? (YES/NO): ") 808 fmt.Scanln(&confirm) 809 if confirm != "YES" { 810 return errors.New("ABORTED: You did not answer YES exactly, in all capitals.") 811 } 812 } 813 814 if err := a.PermanentDeleteAllUsers(); err != nil { 815 return err 816 } 817 CommandPrettyPrintln("All user accounts successfully deleted.") 818 819 auditRec := a.MakeAuditRecord("deleteAllUsers", audit.Success) 820 a.LogAuditRec(auditRec, nil) 821 822 return nil 823 } 824 825 func migrateAuthCmdF(command *cobra.Command, args []string) error { 826 if args[1] == "saml" { 827 return migrateAuthToSamlCmdF(command, args) 828 } 829 return migrateAuthToLdapCmdF(command, args) 830 } 831 832 func migrateAuthToLdapCmdF(command *cobra.Command, args []string) error { 833 a, err := InitDBCommandContextCobra(command) 834 if err != nil { 835 return err 836 } 837 defer a.Srv().Shutdown() 838 839 fromAuth := args[0] 840 matchField := args[2] 841 842 if len(fromAuth) == 0 || (fromAuth != "email" && fromAuth != "gitlab" && fromAuth != "saml") { 843 return errors.New("Invalid from_auth argument") 844 } 845 846 // Email auth in Mattermost system is represented by "" 847 if fromAuth == "email" { 848 fromAuth = "" 849 } 850 851 if len(matchField) == 0 || (matchField != "email" && matchField != "username") { 852 return errors.New("Invalid match_field argument") 853 } 854 855 forceFlag, _ := command.Flags().GetBool("force") 856 dryRunFlag, _ := command.Flags().GetBool("dryRun") 857 858 if migrate := a.AccountMigration(); migrate != nil { 859 if err := migrate.MigrateToLdap(fromAuth, matchField, forceFlag, dryRunFlag); err != nil { 860 return errors.New("Error while migrating users: " + err.Error()) 861 } 862 863 CommandPrettyPrintln("Successfully migrated accounts.") 864 865 if !dryRunFlag { 866 auditRec := a.MakeAuditRecord("migrateAuthToLdap", audit.Success) 867 auditRec.AddMeta("fromAuth", fromAuth) 868 auditRec.AddMeta("matchField", matchField) 869 auditRec.AddMeta("force", forceFlag) 870 a.LogAuditRec(auditRec, nil) 871 } 872 } 873 return nil 874 } 875 876 func migrateAuthToSamlCmdF(command *cobra.Command, args []string) error { 877 a, err := InitDBCommandContextCobra(command) 878 if err != nil { 879 return err 880 } 881 defer a.Srv().Shutdown() 882 883 dryRunFlag, _ := command.Flags().GetBool("dryRun") 884 autoFlag, _ := command.Flags().GetBool("auto") 885 886 matchesFile := "" 887 matches := map[string]string{} 888 if !autoFlag { 889 matchesFile = args[2] 890 891 file, e := ioutil.ReadFile(matchesFile) 892 if e != nil { 893 return errors.New("Invalid users file.") 894 } 895 if json.Unmarshal(file, &matches) != nil { 896 return errors.New("Invalid users file.") 897 } 898 } 899 900 fromAuth := args[0] 901 902 if len(fromAuth) == 0 || (fromAuth != "email" && fromAuth != "gitlab" && fromAuth != "ldap") { 903 return errors.New("Invalid from_auth argument") 904 } 905 906 if autoFlag && !dryRunFlag { 907 var confirm string 908 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):") 909 fmt.Scanln(&confirm) 910 911 if confirm != "YES" { 912 return errors.New("ABORTED: You did not answer YES exactly, in all capitals.") 913 } 914 } 915 916 // Email auth in Mattermost system is represented by "" 917 if fromAuth == "email" { 918 fromAuth = "" 919 } 920 921 if migrate := a.AccountMigration(); migrate != nil { 922 if err := migrate.MigrateToSaml(fromAuth, matches, autoFlag, dryRunFlag); err != nil { 923 return errors.New("Error while migrating users: " + err.Error()) 924 } 925 926 CommandPrettyPrintln("Successfully migrated accounts.") 927 928 if !dryRunFlag { 929 auditRec := a.MakeAuditRecord("migrateAuthToSaml", audit.Success) 930 auditRec.AddMeta("auto", autoFlag) 931 a.LogAuditRec(auditRec, nil) 932 } 933 } 934 return nil 935 } 936 937 func verifyUserCmdF(command *cobra.Command, args []string) error { 938 a, err := InitDBCommandContextCobra(command) 939 if err != nil { 940 return err 941 } 942 defer a.Srv().Shutdown() 943 944 if len(args) < 1 { 945 return errors.New("Expected at least one argument. See help text for details.") 946 } 947 948 users := getUsersFromUserArgs(a, args) 949 950 for i, user := range users { 951 if user == nil { 952 CommandPrintErrorln("Unable to find user '" + args[i] + "'") 953 continue 954 } 955 if _, err := a.Srv().Store.User().VerifyEmail(user.Id, user.Email); err != nil { 956 CommandPrintErrorln("Unable to verify '" + args[i] + "' email. Error: " + err.Error()) 957 } 958 } 959 960 return nil 961 } 962 963 func searchUserCmdF(command *cobra.Command, args []string) error { 964 a, err := InitDBCommandContextCobra(command) 965 if err != nil { 966 return err 967 } 968 defer a.Srv().Shutdown() 969 970 if len(args) < 1 { 971 return errors.New("Expected at least one argument. See help text for details.") 972 } 973 974 users := getUsersFromUserArgs(a, args) 975 976 for i, user := range users { 977 if i > 0 { 978 CommandPrettyPrintln("------------------------------") 979 } 980 if user == nil { 981 CommandPrintErrorln("Unable to find user '" + args[i] + "'") 982 continue 983 } 984 985 CommandPrettyPrintln("id: " + user.Id) 986 CommandPrettyPrintln("username: " + user.Username) 987 CommandPrettyPrintln("nickname: " + user.Nickname) 988 CommandPrettyPrintln("position: " + user.Position) 989 CommandPrettyPrintln("first_name: " + user.FirstName) 990 CommandPrettyPrintln("last_name: " + user.LastName) 991 CommandPrettyPrintln("email: " + user.Email) 992 CommandPrettyPrintln("auth_service: " + user.AuthService) 993 } 994 995 return nil 996 }