github.com/minio/mc@v0.0.0-20240503112107-b471de8d1882/cmd/admin-user-add.go (about) 1 // Copyright (c) 2015-2022 MinIO, Inc. 2 // 3 // This file is part of MinIO Object Storage stack 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package cmd 19 20 import ( 21 "bufio" 22 "fmt" 23 "os" 24 "strings" 25 26 "github.com/fatih/color" 27 "github.com/minio/cli" 28 json "github.com/minio/colorjson" 29 "github.com/minio/mc/pkg/probe" 30 "github.com/minio/pkg/v2/console" 31 "golang.org/x/term" 32 ) 33 34 var adminUserAddCmd = cli.Command{ 35 Name: "add", 36 Usage: "add a new user", 37 Action: mainAdminUserAdd, 38 OnUsageError: onUsageError, 39 Before: setGlobalsFromContext, 40 Flags: globalFlags, 41 CustomHelpTemplate: `NAME: 42 {{.HelpName}} - {{.Usage}} 43 44 USAGE: 45 {{.HelpName}} TARGET ACCESSKEY SECRETKEY 46 47 ACCESSKEY: 48 Also called as username. 49 50 SECRETKEY: 51 Also called as password. 52 53 FLAGS: 54 {{range .VisibleFlags}}{{.}} 55 {{end}} 56 EXAMPLES: 57 1. Add a new user 'foobar' to MinIO server. 58 {{.DisableHistory}} 59 {{.Prompt}} {{.HelpName}} myminio foobar foo12345 60 {{.EnableHistory}} 61 62 2. Add a new user 'foobar' to MinIO server, prompting for keys. 63 {{.Prompt}} {{.HelpName}} myminio 64 Enter Access Key: foobar 65 Enter Secret Key: foobar12345 66 67 3. Add a new user 'foobar' to MinIO server using piped keys. 68 {{.DisableHistory}} 69 {{.Prompt}} echo -e "foobar\nfoobar12345" | {{.HelpName}} myminio 70 {{.EnableHistory}} 71 72 4. Add a new user 'foobar' to MinIO server, then attach IAM policy "writeonly". 73 {{.Prompt}} {{.HelpName}} myminio foobar foo12345 74 {{.Prompt}} mc admin policy attach myminio writeonly --user foobar 75 `, 76 } 77 78 // checkAdminUserAddSyntax - validate all the passed arguments 79 func checkAdminUserAddSyntax(ctx *cli.Context) { 80 argsNr := len(ctx.Args()) 81 if argsNr > 3 || argsNr < 1 { 82 showCommandHelpAndExit(ctx, 1) 83 } 84 } 85 86 // userGroup container for content message structure 87 type userGroup struct { 88 Name string `json:"name,omitempty"` 89 Policies []string `json:"policies,omitempty"` 90 } 91 92 // userMessage container for content message structure 93 type userMessage struct { 94 op string 95 Status string `json:"status"` // TODO: remove this? 96 AccessKey string `json:"accessKey,omitempty"` 97 SecretKey string `json:"secretKey,omitempty"` 98 PolicyName string `json:"policyName,omitempty"` 99 UserStatus string `json:"userStatus,omitempty"` 100 MemberOf []userGroup `json:"memberOf,omitempty"` 101 Authentication string `json:"authentication,omitempty"` 102 } 103 104 func (u userMessage) String() string { 105 switch u.op { 106 case "list": 107 userFieldMaxLen := 9 108 accessFieldMaxLen := 20 109 policyFieldMaxLen := 20 110 111 // Create a new pretty table with cols configuration 112 return newPrettyTable(" ", 113 Field{"UserStatus", userFieldMaxLen}, 114 Field{"AccessKey", accessFieldMaxLen}, 115 Field{"PolicyName", policyFieldMaxLen}, 116 ).buildRow(u.UserStatus, u.AccessKey, u.PolicyName) 117 case "info": 118 memberOf := []string{} 119 for _, group := range u.MemberOf { 120 memberOf = append(memberOf, group.Name) 121 } 122 lines := []string{ 123 fmt.Sprintf("AccessKey: %s", u.AccessKey), 124 fmt.Sprintf("Status: %s", u.UserStatus), 125 fmt.Sprintf("PolicyName: %s", u.PolicyName), 126 fmt.Sprintf("MemberOf: %s", memberOf), 127 } 128 if u.Authentication != "" { 129 lines = append(lines, fmt.Sprintf("Authentication: %s", u.Authentication)) 130 } 131 return console.Colorize("UserMessage", strings.Join(lines, "\n")) 132 case "remove": 133 return console.Colorize("UserMessage", "Removed user `"+u.AccessKey+"` successfully.") 134 case "disable": 135 return console.Colorize("UserMessage", "Disabled user `"+u.AccessKey+"` successfully.") 136 case "enable": 137 return console.Colorize("UserMessage", "Enabled user `"+u.AccessKey+"` successfully.") 138 case "add": 139 return console.Colorize("UserMessage", "Added user `"+u.AccessKey+"` successfully.") 140 } 141 return "" 142 } 143 144 func (u userMessage) JSON() string { 145 u.Status = "success" 146 jsonMessageBytes, e := json.MarshalIndent(u, "", " ") 147 fatalIf(probe.NewError(e), "Unable to marshal into JSON.") 148 149 return string(jsonMessageBytes) 150 } 151 152 // fetchUserKeys - returns the access and secret key 153 func fetchUserKeys(args cli.Args) (string, string) { 154 accessKey := "" 155 secretKey := "" 156 console.SetColor(cred, color.New(color.FgYellow, color.Italic)) 157 isTerminal := term.IsTerminal(int(os.Stdin.Fd())) 158 reader := bufio.NewReader(os.Stdin) 159 160 argCount := len(args) 161 162 if argCount == 1 { 163 if isTerminal { 164 fmt.Printf("%s", console.Colorize(cred, "Enter Access Key: ")) 165 } 166 value, _, _ := reader.ReadLine() 167 accessKey = string(value) 168 } else { 169 accessKey = args.Get(1) 170 } 171 172 if argCount == 1 || argCount == 2 { 173 if isTerminal { 174 fmt.Printf("%s", console.Colorize(cred, "Enter Secret Key: ")) 175 bytePassword, _ := term.ReadPassword(int(os.Stdin.Fd())) 176 fmt.Printf("\n") 177 secretKey = string(bytePassword) 178 } else { 179 value, _, _ := reader.ReadLine() 180 secretKey = string(value) 181 } 182 } else { 183 secretKey = args.Get(2) 184 } 185 186 return accessKey, secretKey 187 } 188 189 // mainAdminUserAdd is the handle for "mc admin user add" command. 190 func mainAdminUserAdd(ctx *cli.Context) error { 191 checkAdminUserAddSyntax(ctx) 192 193 console.SetColor("UserMessage", color.New(color.FgGreen)) 194 195 // Get the alias parameter from cli 196 args := ctx.Args() 197 aliasedURL := args.Get(0) 198 accessKey, secretKey := fetchUserKeys(args) 199 200 // Create a new MinIO Admin Client 201 client, err := newAdminClient(aliasedURL) 202 fatalIf(err, "Unable to initialize admin connection.") 203 204 fatalIf(probe.NewError(client.AddUser(globalContext, accessKey, secretKey)).Trace(args...), "Unable to add new user") 205 206 printMsg(userMessage{ 207 op: ctx.Command.Name, 208 AccessKey: accessKey, 209 SecretKey: secretKey, 210 UserStatus: "enabled", 211 }) 212 213 return nil 214 }