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 }