github.com/psyb0t/mattermost-server@v4.6.1-0.20180125161845-5503a1351abf+incompatible/cmd/platform/user.go (about) 1 // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 package main 4 5 import ( 6 "errors" 7 "fmt" 8 9 "github.com/mattermost/mattermost-server/app" 10 "github.com/mattermost/mattermost-server/model" 11 "github.com/spf13/cobra" 12 ) 13 14 var userCmd = &cobra.Command{ 15 Use: "user", 16 Short: "Management of users", 17 } 18 19 var userActivateCmd = &cobra.Command{ 20 Use: "activate [emails, usernames, userIds]", 21 Short: "Activate users", 22 Long: "Activate users that have been deactivated.", 23 Example: ` user activate user@example.com 24 user activate username`, 25 RunE: userActivateCmdF, 26 } 27 28 var userDeactivateCmd = &cobra.Command{ 29 Use: "deactivate [emails, usernames, userIds]", 30 Short: "Deactivate users", 31 Long: "Deactivate users. Deactivated users are immediately logged out of all sessions and are unable to log back in.", 32 Example: ` user deactivate user@example.com 33 user deactivate username`, 34 RunE: userDeactivateCmdF, 35 } 36 37 var userCreateCmd = &cobra.Command{ 38 Use: "create", 39 Short: "Create a user", 40 Long: "Create a user", 41 Example: ` user create --email user@example.com --username userexample --password Password1`, 42 RunE: userCreateCmdF, 43 } 44 45 var userInviteCmd = &cobra.Command{ 46 Use: "invite [email] [teams]", 47 Short: "Send user an email invite to a team.", 48 Long: `Send user an email invite to a team. 49 You can invite a user to multiple teams by listing them. 50 You can specify teams by name or ID.`, 51 Example: ` user invite user@example.com myteam 52 user invite user@example.com myteam1 myteam2`, 53 RunE: userInviteCmdF, 54 } 55 56 var resetUserPasswordCmd = &cobra.Command{ 57 Use: "password [user] [password]", 58 Short: "Set a user's password", 59 Long: "Set a user's password", 60 Example: " user password user@example.com Password1", 61 RunE: resetUserPasswordCmdF, 62 } 63 64 var resetUserMfaCmd = &cobra.Command{ 65 Use: "resetmfa [users]", 66 Short: "Turn off MFA", 67 Long: `Turn off multi-factor authentication for a user. 68 If MFA enforcement is enabled, the user will be forced to re-enable MFA as soon as they login.`, 69 Example: " user resetmfa user@example.com", 70 RunE: resetUserMfaCmdF, 71 } 72 73 var deleteUserCmd = &cobra.Command{ 74 Use: "delete [users]", 75 Short: "Delete users and all posts", 76 Long: "Permanently delete user and all related information including posts.", 77 Example: " user delete user@example.com", 78 RunE: deleteUserCmdF, 79 } 80 81 var deleteAllUsersCmd = &cobra.Command{ 82 Use: "deleteall", 83 Short: "Delete all users and all posts", 84 Long: "Permanently delete all users and all related information including posts.", 85 Example: " user deleteall", 86 RunE: deleteAllUsersCommandF, 87 } 88 89 var migrateAuthCmd = &cobra.Command{ 90 Use: "migrate_auth [from_auth] [to_auth] [match_field]", 91 Short: "Mass migrate user accounts authentication type", 92 Long: `Migrates accounts from one authentication provider to another. For example, you can upgrade your authentication provider from email to ldap. 93 94 from_auth: 95 The authentication service to migrate users accounts from. 96 Supported options: email, gitlab, saml. 97 98 to_auth: 99 The authentication service to migrate users to. 100 Supported options: ldap. 101 102 match_field: 103 The field that is guaranteed to be the same in both authentication services. For example, if the users emails are consistent set to email. 104 Supported options: email, username. 105 106 Will display any accounts that are not migrated successfully.`, 107 Example: " user migrate_auth email ladp email", 108 RunE: migrateAuthCmdF, 109 } 110 111 var verifyUserCmd = &cobra.Command{ 112 Use: "verify [users]", 113 Short: "Verify email of users", 114 Long: "Verify the emails of some users.", 115 Example: " user verify user1", 116 RunE: verifyUserCmdF, 117 } 118 119 var searchUserCmd = &cobra.Command{ 120 Use: "search [users]", 121 Short: "Search for users", 122 Long: "Search for users based on username, email, or user ID.", 123 Example: " user search user1@mail.com user2@mail.com", 124 RunE: searchUserCmdF, 125 } 126 127 func init() { 128 userCreateCmd.Flags().String("username", "", "Required. Username for the new user account.") 129 userCreateCmd.Flags().String("email", "", "Required. The email address for the new user account.") 130 userCreateCmd.Flags().String("password", "", "Required. The password for the new user account.") 131 userCreateCmd.Flags().String("nickname", "", "Optional. The nickname for the new user account.") 132 userCreateCmd.Flags().String("firstname", "", "Optional. The first name for the new user account.") 133 userCreateCmd.Flags().String("lastname", "", "Optional. The last name for the new user account.") 134 userCreateCmd.Flags().String("locale", "", "Optional. The locale (ex: en, fr) for the new user account.") 135 userCreateCmd.Flags().Bool("system_admin", false, "Optional. If supplied, the new user will be a system administrator. Defaults to false.") 136 137 deleteUserCmd.Flags().Bool("confirm", false, "Confirm you really want to delete the user and a DB backup has been performed.") 138 139 deleteAllUsersCmd.Flags().Bool("confirm", false, "Confirm you really want to delete the user and a DB backup has been performed.") 140 141 migrateAuthCmd.Flags().Bool("force", false, "Force the migration to occour even if there are duplicates on the LDAP server. Duplicates will not be migrated.") 142 143 userCmd.AddCommand( 144 userActivateCmd, 145 userDeactivateCmd, 146 userCreateCmd, 147 userInviteCmd, 148 resetUserPasswordCmd, 149 resetUserMfaCmd, 150 deleteUserCmd, 151 deleteAllUsersCmd, 152 migrateAuthCmd, 153 verifyUserCmd, 154 searchUserCmd, 155 ) 156 } 157 158 func userActivateCmdF(cmd *cobra.Command, args []string) error { 159 a, err := initDBCommandContextCobra(cmd) 160 if err != nil { 161 return err 162 } 163 164 if len(args) < 1 { 165 return errors.New("Expected at least one argument. See help text for details.") 166 } 167 168 changeUsersActiveStatus(a, args, true) 169 return nil 170 } 171 172 func changeUsersActiveStatus(a *app.App, userArgs []string, active bool) { 173 users := getUsersFromUserArgs(a, userArgs) 174 for i, user := range users { 175 err := changeUserActiveStatus(a, user, userArgs[i], active) 176 177 if err != nil { 178 CommandPrintErrorln(err.Error()) 179 } 180 } 181 } 182 183 func changeUserActiveStatus(a *app.App, user *model.User, userArg string, activate bool) error { 184 if user == nil { 185 return fmt.Errorf("Can't find user '%v'", userArg) 186 } 187 if user.IsSSOUser() { 188 fmt.Println("You must also deactivate this user in the SSO provider or they will be reactivated on next login or sync.") 189 } 190 if _, err := a.UpdateActive(user, activate); err != nil { 191 return fmt.Errorf("Unable to change activation status of user: %v", userArg) 192 } 193 194 return nil 195 } 196 197 func userDeactivateCmdF(cmd *cobra.Command, args []string) error { 198 a, err := initDBCommandContextCobra(cmd) 199 if err != nil { 200 return err 201 } 202 203 if len(args) < 1 { 204 return errors.New("Expected at least one argument. See help text for details.") 205 } 206 207 changeUsersActiveStatus(a, args, false) 208 return nil 209 } 210 211 func userCreateCmdF(cmd *cobra.Command, args []string) error { 212 a, err := initDBCommandContextCobra(cmd) 213 if err != nil { 214 return err 215 } 216 217 username, erru := cmd.Flags().GetString("username") 218 if erru != nil || username == "" { 219 return errors.New("Username is required") 220 } 221 email, erre := cmd.Flags().GetString("email") 222 if erre != nil || email == "" { 223 return errors.New("Email is required") 224 } 225 password, errp := cmd.Flags().GetString("password") 226 if errp != nil || password == "" { 227 return errors.New("Password is required") 228 } 229 nickname, _ := cmd.Flags().GetString("nickname") 230 firstname, _ := cmd.Flags().GetString("firstname") 231 lastname, _ := cmd.Flags().GetString("lastname") 232 locale, _ := cmd.Flags().GetString("locale") 233 systemAdmin, _ := cmd.Flags().GetBool("system_admin") 234 235 user := &model.User{ 236 Username: username, 237 Email: email, 238 Password: password, 239 Nickname: nickname, 240 FirstName: firstname, 241 LastName: lastname, 242 Locale: locale, 243 } 244 245 if ruser, err := a.CreateUser(user); err != nil { 246 return errors.New("Unable to create user. Error: " + err.Error()) 247 } else if systemAdmin { 248 a.UpdateUserRoles(ruser.Id, "system_user system_admin", false) 249 } 250 251 CommandPrettyPrintln("Created User") 252 253 return nil 254 } 255 256 func userInviteCmdF(cmd *cobra.Command, args []string) error { 257 a, err := initDBCommandContextCobra(cmd) 258 if err != nil { 259 return err 260 } 261 262 if len(args) < 2 { 263 return errors.New("Expected at least two arguments. See help text for details.") 264 } 265 266 email := args[0] 267 if !model.IsValidEmail(email) { 268 return errors.New("Invalid email") 269 } 270 271 teams := getTeamsFromTeamArgs(a, args[1:]) 272 for i, team := range teams { 273 err := inviteUser(a, email, team, args[i+1]) 274 275 if err != nil { 276 CommandPrintErrorln(err.Error()) 277 } 278 } 279 280 return nil 281 } 282 283 func inviteUser(a *app.App, email string, team *model.Team, teamArg string) error { 284 invites := []string{email} 285 if team == nil { 286 return fmt.Errorf("Can't find team '%v'", teamArg) 287 } 288 289 a.SendInviteEmails(team, "Administrator", invites, *a.Config().ServiceSettings.SiteURL) 290 CommandPrettyPrintln("Invites may or may not have been sent.") 291 292 return nil 293 } 294 295 func resetUserPasswordCmdF(cmd *cobra.Command, args []string) error { 296 a, err := initDBCommandContextCobra(cmd) 297 if err != nil { 298 return err 299 } 300 301 if len(args) != 2 { 302 return errors.New("Expected two arguments. See help text for details.") 303 } 304 305 user := getUserFromUserArg(a, args[0]) 306 if user == nil { 307 return errors.New("Unable to find user '" + args[0] + "'") 308 } 309 password := args[1] 310 311 if result := <-a.Srv.Store.User().UpdatePassword(user.Id, model.HashPassword(password)); result.Err != nil { 312 return result.Err 313 } 314 315 return nil 316 } 317 318 func resetUserMfaCmdF(cmd *cobra.Command, args []string) error { 319 a, err := initDBCommandContextCobra(cmd) 320 if err != nil { 321 return err 322 } 323 324 if len(args) < 1 { 325 return errors.New("Expected at least one argument. See help text for details.") 326 } 327 328 users := getUsersFromUserArgs(a, args) 329 330 for i, user := range users { 331 if user == nil { 332 return errors.New("Unable to find user '" + args[i] + "'") 333 } 334 335 if err := a.DeactivateMfa(user.Id); err != nil { 336 return err 337 } 338 } 339 340 return nil 341 } 342 343 func deleteUserCmdF(cmd *cobra.Command, args []string) error { 344 a, err := initDBCommandContextCobra(cmd) 345 if err != nil { 346 return err 347 } 348 349 if len(args) < 1 { 350 return errors.New("Expected at least one argument. See help text for details.") 351 } 352 353 confirmFlag, _ := cmd.Flags().GetBool("confirm") 354 if !confirmFlag { 355 var confirm string 356 CommandPrettyPrintln("Have you performed a database backup? (YES/NO): ") 357 fmt.Scanln(&confirm) 358 359 if confirm != "YES" { 360 return errors.New("ABORTED: You did not answer YES exactly, in all capitals.") 361 } 362 CommandPrettyPrintln("Are you sure you want to permanently delete the specified users? (YES/NO): ") 363 fmt.Scanln(&confirm) 364 if confirm != "YES" { 365 return errors.New("ABORTED: You did not answer YES exactly, in all capitals.") 366 } 367 } 368 369 users := getUsersFromUserArgs(a, args) 370 371 for i, user := range users { 372 if user == nil { 373 return errors.New("Unable to find user '" + args[i] + "'") 374 } 375 376 if err := a.PermanentDeleteUser(user); err != nil { 377 return err 378 } 379 } 380 381 return nil 382 } 383 384 func deleteAllUsersCommandF(cmd *cobra.Command, args []string) error { 385 a, err := initDBCommandContextCobra(cmd) 386 if err != nil { 387 return err 388 } 389 390 if len(args) > 0 { 391 return errors.New("Expected zero arguments.") 392 } 393 394 confirmFlag, _ := cmd.Flags().GetBool("confirm") 395 if !confirmFlag { 396 var confirm string 397 CommandPrettyPrintln("Have you performed a database backup? (YES/NO): ") 398 fmt.Scanln(&confirm) 399 400 if confirm != "YES" { 401 return errors.New("ABORTED: You did not answer YES exactly, in all capitals.") 402 } 403 CommandPrettyPrintln("Are you sure you want to permanently delete all user accounts? (YES/NO): ") 404 fmt.Scanln(&confirm) 405 if confirm != "YES" { 406 return errors.New("ABORTED: You did not answer YES exactly, in all capitals.") 407 } 408 } 409 410 if err := a.PermanentDeleteAllUsers(); err != nil { 411 return err 412 } 413 414 CommandPrettyPrintln("All user accounts successfully deleted.") 415 return nil 416 } 417 418 func migrateAuthCmdF(cmd *cobra.Command, args []string) error { 419 a, err := initDBCommandContextCobra(cmd) 420 if err != nil { 421 return err 422 } 423 424 if len(args) != 3 { 425 return errors.New("Expected three arguments. See help text for details.") 426 } 427 428 fromAuth := args[0] 429 toAuth := args[1] 430 matchField := args[2] 431 432 if len(fromAuth) == 0 || (fromAuth != "email" && fromAuth != "gitlab" && fromAuth != "saml") { 433 return errors.New("Invalid from_auth argument") 434 } 435 436 if len(toAuth) == 0 || toAuth != "ldap" { 437 return errors.New("Invalid to_auth argument") 438 } 439 440 // Email auth in Mattermost system is represented by "" 441 if fromAuth == "email" { 442 fromAuth = "" 443 } 444 445 if len(matchField) == 0 || (matchField != "email" && matchField != "username") { 446 return errors.New("Invalid match_field argument") 447 } 448 449 forceFlag, _ := cmd.Flags().GetBool("force") 450 451 if migrate := a.AccountMigration; migrate != nil { 452 if err := migrate.MigrateToLdap(fromAuth, matchField, forceFlag); err != nil { 453 return errors.New("Error while migrating users: " + err.Error()) 454 } 455 456 CommandPrettyPrintln("Sucessfully migrated accounts.") 457 } 458 459 return nil 460 } 461 462 func verifyUserCmdF(cmd *cobra.Command, args []string) error { 463 a, err := initDBCommandContextCobra(cmd) 464 if err != nil { 465 return err 466 } 467 468 if len(args) < 1 { 469 return errors.New("Expected at least one argument. See help text for details.") 470 } 471 472 users := getUsersFromUserArgs(a, args) 473 474 for i, user := range users { 475 if user == nil { 476 CommandPrintErrorln("Unable to find user '" + args[i] + "'") 477 continue 478 } 479 if cresult := <-a.Srv.Store.User().VerifyEmail(user.Id); cresult.Err != nil { 480 CommandPrintErrorln("Unable to verify '" + args[i] + "' email. Error: " + cresult.Err.Error()) 481 } 482 } 483 484 return nil 485 } 486 487 func searchUserCmdF(cmd *cobra.Command, args []string) error { 488 a, err := initDBCommandContextCobra(cmd) 489 if err != nil { 490 return err 491 } 492 493 if len(args) < 1 { 494 return errors.New("Expected at least one argument. See help text for details.") 495 } 496 497 users := getUsersFromUserArgs(a, args) 498 499 for i, user := range users { 500 if i > 0 { 501 CommandPrettyPrintln("------------------------------") 502 } 503 if user == nil { 504 CommandPrintErrorln("Unable to find user '" + args[i] + "'") 505 continue 506 } 507 508 CommandPrettyPrintln("id: " + user.Id) 509 CommandPrettyPrintln("username: " + user.Username) 510 CommandPrettyPrintln("nickname: " + user.Nickname) 511 CommandPrettyPrintln("position: " + user.Position) 512 CommandPrettyPrintln("first_name: " + user.FirstName) 513 CommandPrettyPrintln("last_name: " + user.LastName) 514 CommandPrettyPrintln("email: " + user.Email) 515 CommandPrettyPrintln("auth_service: " + user.AuthService) 516 } 517 518 return nil 519 }