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