github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/cmd/juju/user/add.go (about)

     1  // Copyright 2012-2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package user
     5  
     6  import (
     7  	"encoding/asn1"
     8  	"encoding/base64"
     9  	"fmt"
    10  
    11  	"github.com/juju/cmd"
    12  	"github.com/juju/errors"
    13  	"gopkg.in/juju/names.v2"
    14  
    15  	"github.com/juju/juju/cmd/juju/block"
    16  	"github.com/juju/juju/cmd/modelcmd"
    17  	"github.com/juju/juju/jujuclient"
    18  )
    19  
    20  var usageSummary = `
    21  Adds a Juju user to a controller.`[1:]
    22  
    23  const usageDetails = "A `juju register` command will be printed, which must be executed by the" + `
    24  user to complete the registration process. The user's details are stored
    25  within the shared model, and will be removed when the model is destroyed.
    26  
    27  Some machine providers will require the user to be in possession of certain
    28  credentials in order to create a model.
    29  
    30  Examples:
    31      juju add-user bob
    32      juju add-user --controller mycontroller bob
    33  
    34  See also:
    35      register
    36      grant
    37      users
    38      show-user
    39      disable-user
    40      enable-user
    41      change-user-password
    42      remove-user`
    43  
    44  // AddUserAPI defines the usermanager API methods that the add command uses.
    45  type AddUserAPI interface {
    46  	AddUser(username, displayName, password string) (names.UserTag, []byte, error)
    47  	Close() error
    48  }
    49  
    50  func NewAddCommand() cmd.Command {
    51  	return modelcmd.WrapController(&addCommand{})
    52  }
    53  
    54  // addCommand adds new users into a Juju Server.
    55  type addCommand struct {
    56  	modelcmd.ControllerCommandBase
    57  	api         AddUserAPI
    58  	User        string
    59  	DisplayName string
    60  }
    61  
    62  // Info implements Command.Info.
    63  func (c *addCommand) Info() *cmd.Info {
    64  	return &cmd.Info{
    65  		Name:    "add-user",
    66  		Args:    "<user name> [<display name>]",
    67  		Purpose: usageSummary,
    68  		Doc:     usageDetails,
    69  	}
    70  }
    71  
    72  // Init implements Command.Init.
    73  func (c *addCommand) Init(args []string) error {
    74  	if len(args) == 0 {
    75  		return errors.Errorf("no username supplied")
    76  	}
    77  
    78  	c.User, args = args[0], args[1:]
    79  	if len(args) > 0 {
    80  		c.DisplayName, args = args[0], args[1:]
    81  	}
    82  	return cmd.CheckEmpty(args)
    83  }
    84  
    85  // Run implements Command.Run.
    86  func (c *addCommand) Run(ctx *cmd.Context) error {
    87  	api := c.api
    88  	if api == nil {
    89  		var err error
    90  		api, err = c.NewUserManagerAPIClient()
    91  		if err != nil {
    92  			return errors.Trace(err)
    93  		}
    94  		defer api.Close()
    95  	}
    96  
    97  	// Add a user without a password. This will generate a temporary
    98  	// secret key, which we'll print out for the user to supply to
    99  	// "juju register".
   100  	_, secretKey, err := api.AddUser(c.User, c.DisplayName, "")
   101  	if err != nil {
   102  		return block.ProcessBlockedError(err, block.BlockChange)
   103  	}
   104  
   105  	displayName := c.User
   106  	if c.DisplayName != "" {
   107  		displayName = fmt.Sprintf("%s (%s)", c.DisplayName, c.User)
   108  	}
   109  
   110  	// Generate the base64-encoded string for the user to pass to
   111  	// "juju register". We marshal the information using ASN.1
   112  	// to keep the size down, since we need to encode binary data.
   113  	controllerDetails, err := c.ClientStore().ControllerByName(c.ControllerName())
   114  	if err != nil {
   115  		return errors.Trace(err)
   116  	}
   117  	registrationInfo := jujuclient.RegistrationInfo{
   118  		User:           c.User,
   119  		Addrs:          controllerDetails.APIEndpoints,
   120  		SecretKey:      secretKey,
   121  		ControllerName: c.ControllerName(),
   122  	}
   123  	registrationData, err := asn1.Marshal(registrationInfo)
   124  	if err != nil {
   125  		return errors.Trace(err)
   126  	}
   127  
   128  	// Use URLEncoding so we don't get + or / in the string,
   129  	// and pad with zero bytes so we don't get =; this all
   130  	// makes it easier to copy & paste in a terminal.
   131  	//
   132  	// The embedded ASN.1 data is length-encoded, so the
   133  	// padding will not complicate decoding.
   134  	remainder := len(registrationData) % 3
   135  	for remainder > 0 {
   136  		registrationData = append(registrationData, 0)
   137  		remainder--
   138  	}
   139  	base64RegistrationData := base64.URLEncoding.EncodeToString(
   140  		registrationData,
   141  	)
   142  
   143  	fmt.Fprintf(ctx.Stdout, "User %q added\n", displayName)
   144  	fmt.Fprintf(ctx.Stdout, "Please send this command to %v:\n", c.User)
   145  	fmt.Fprintf(ctx.Stdout, "    juju register %s\n",
   146  		base64RegistrationData,
   147  	)
   148  	fmt.Fprintf(ctx.Stdout, `
   149  %q has not been granted access to any models. You can use "juju grant" to grant access.
   150  `, displayName)
   151  
   152  	return nil
   153  }