github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/user/logout.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package user 5 6 import ( 7 "github.com/juju/cmd" 8 "github.com/juju/errors" 9 "github.com/juju/gnuflag" 10 11 jujucmd "github.com/juju/juju/cmd" 12 "github.com/juju/juju/cmd/modelcmd" 13 "github.com/juju/juju/jujuclient" 14 ) 15 16 const logoutDoc = ` 17 If another client has logged in as the same user, they will remain logged 18 in. This command only affects the local client. 19 20 The command will fail if the user has not yet set a password 21 (` + "`juju change-user-password`" + `). This scenario is only possible after 22 ` + "`juju bootstrap`" + `since ` + "`juju register`" + ` sets a password. The 23 failing behaviour can be overridden with the '--force' option. 24 25 If the same user is logged in with another client system, that user session 26 will not be affected by this command; it only affects the local client. 27 28 By default, the controller is the current controller. 29 30 Examples: 31 juju logout 32 33 See also: 34 change-user-password 35 login 36 37 ` 38 39 // NewLogoutCommand returns a new cmd.Command to handle "juju logout". 40 func NewLogoutCommand() cmd.Command { 41 return modelcmd.WrapController(&logoutCommand{}) 42 } 43 44 // logoutCommand changes the password for a user. 45 type logoutCommand struct { 46 modelcmd.ControllerCommandBase 47 Force bool 48 } 49 50 // Info implements Command.Info. 51 func (c *logoutCommand) Info() *cmd.Info { 52 return jujucmd.Info(&cmd.Info{ 53 Name: "logout", 54 Purpose: "Logs a Juju user out of a controller.", 55 Doc: logoutDoc, 56 }) 57 } 58 59 // Init implements Command.Init. 60 func (c *logoutCommand) Init(args []string) error { 61 return cmd.CheckEmpty(args) 62 } 63 64 // SetFlags implements Command.SetFlags. 65 func (c *logoutCommand) SetFlags(f *gnuflag.FlagSet) { 66 c.ControllerCommandBase.SetFlags(f) 67 f.BoolVar(&c.Force, "force", false, "Force logout when a locally recorded password is detected") 68 } 69 70 // Run implements Command.Run. 71 func (c *logoutCommand) Run(ctx *cmd.Context) error { 72 controllerName, err := c.ControllerName() 73 if err != nil { 74 return errors.Trace(err) 75 } 76 store := c.ClientStore() 77 if err := c.logout(store, controllerName); err != nil { 78 return errors.Trace(err) 79 } 80 81 // Count the number of logged-into controllers to inform the user. 82 var loggedInCount int 83 controllers, err := store.AllControllers() 84 if err != nil { 85 return errors.Trace(err) 86 } 87 for name := range controllers { 88 if name == controllerName { 89 continue 90 } 91 _, err := store.AccountDetails(name) 92 if errors.IsNotFound(err) { 93 continue 94 } else if err != nil { 95 return errors.Trace(err) 96 } 97 loggedInCount++ 98 } 99 switch loggedInCount { 100 case 0: 101 ctx.Infof("Logged out. You are no longer logged into any controllers.") 102 case 1: 103 ctx.Infof("Logged out. You are still logged into 1 controller.") 104 default: 105 ctx.Infof("Logged out. You are still logged into %d controllers.", loggedInCount) 106 } 107 return nil 108 } 109 110 func (c *logoutCommand) logout(store jujuclient.ClientStore, controllerName string) error { 111 accountDetails, err := store.AccountDetails(controllerName) 112 if errors.IsNotFound(err) { 113 // Not logged in; nothing else to do. 114 return nil 115 } else if err != nil { 116 return errors.Trace(err) 117 } 118 119 // We first ensure that the user has a macaroon, which implies 120 // they know their password. If they have just bootstrapped, 121 // they will have a randomly generated password which they will 122 // be unaware of. 123 if accountDetails.Password != "" && !c.Force { 124 return errors.New(`preventing account loss 125 126 It appears that you have not changed the password for 127 your account. If this is the case, change the password 128 first before logging out, so that you can log in again 129 afterwards. To change your password, run the command 130 "juju change-user-password". 131 132 If you are sure you want to log out, and it is safe to 133 clear the credentials from the client, then you can run 134 this command again with the "--force" option. 135 `) 136 } 137 138 if err := c.ClearControllerMacaroons(c.ClientStore(), controllerName); err != nil { 139 return errors.Trace(err) 140 } 141 142 // Remove the account credentials. 143 if err := store.RemoveAccount(controllerName); err != nil { 144 return errors.Annotate(err, "failed to clear credentials") 145 } 146 return nil 147 }