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