github.com/minio/mc@v0.0.0-20240503112107-b471de8d1882/cmd/idp-ldap-accesskey-create.go (about) 1 // Copyright (c) 2015-2023 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 "bytes" 22 "fmt" 23 "os" 24 "time" 25 26 "github.com/minio/cli" 27 "github.com/minio/madmin-go/v3" 28 "github.com/minio/mc/pkg/probe" 29 "github.com/minio/pkg/v2/policy" 30 ) 31 32 var idpLdapAccesskeyCreateFlags = []cli.Flag{ 33 cli.StringFlag{ 34 Name: "access-key", 35 Usage: "set an access key for the account", 36 }, 37 cli.StringFlag{ 38 Name: "secret-key", 39 Usage: "set a secret key for the account", 40 }, 41 cli.StringFlag{ 42 Name: "policy", 43 Usage: "path to a JSON policy file", 44 }, 45 cli.StringFlag{ 46 Name: "name", 47 Usage: "friendly name for the account", 48 }, 49 cli.StringFlag{ 50 Name: "description", 51 Usage: "description for the account", 52 }, 53 cli.StringFlag{ 54 Name: "expiry-duration", 55 Usage: "duration before the access key expires", 56 }, 57 cli.StringFlag{ 58 Name: "expiry", 59 Usage: "expiry date for the access key", 60 }, 61 cli.BoolFlag{ 62 Name: "login", 63 Usage: "log in using ldap credentials to generate access key pair for future use", 64 Hidden: true, 65 }, 66 } 67 68 var idpLdapAccesskeyCreateCmd = cli.Command{ 69 Name: "create", 70 Usage: "create access key pairs for LDAP", 71 Action: mainIDPLdapAccesskeyCreate, 72 Before: setGlobalsFromContext, 73 Flags: append(idpLdapAccesskeyCreateFlags, globalFlags...), 74 OnUsageError: onUsageError, 75 CustomHelpTemplate: `NAME: 76 {{.HelpName}} - {{.Usage}} 77 78 USAGE: 79 {{.HelpName}} [FLAGS] [TARGET] 80 81 FLAGS: 82 {{range .VisibleFlags}}{{.}} 83 {{end}} 84 EXAMPLES: 85 1. Create a new access key pair with the same policy as the authenticated user 86 {{.Prompt}} {{.HelpName}} local/ 87 2. Create a new access key pair with custom access key and secret key 88 {{.Prompt}} {{.HelpName}} local/ --access-key myaccesskey --secret-key mysecretkey 89 4. Create a new access key pair for user with username "james" that expires in 1 day 90 {{.Prompt}} {{.HelpName}} local/ james --expiry-duration 24h 91 5. Create a new access key pair for authenticated user that expires on 2021-01-01 92 {{.Prompt}} {{.HelpName}} --expiry 2021-01-01 93 `, 94 } 95 96 func mainIDPLdapAccesskeyCreate(ctx *cli.Context) error { 97 if len(ctx.Args()) == 0 || len(ctx.Args()) > 2 { 98 showCommandHelpAndExit(ctx, 1) // last argument is exit code 99 } 100 101 args := ctx.Args() 102 aliasedURL := args.Get(0) 103 targetUser := args.Get(1) 104 105 if ctx.Bool("login") { 106 deprecatedError("mc idp ldap accesskey create-with-login") 107 } 108 109 opts := accessKeyCreateOpts(ctx, targetUser) 110 client, err := newAdminClient(aliasedURL) 111 fatalIf(err, "Unable to initialize admin connection.") 112 113 res, e := client.AddServiceAccountLDAP(globalContext, opts) 114 fatalIf(probe.NewError(e), "Unable to add service account.") 115 116 m := ldapAccesskeyMessage{ 117 op: "create", 118 Status: "success", 119 AccessKey: res.AccessKey, 120 SecretKey: res.SecretKey, 121 Expiration: &res.Expiration, 122 Name: opts.Name, 123 Description: opts.Description, 124 } 125 printMsg(m) 126 127 return nil 128 } 129 130 func accessKeyCreateOpts(ctx *cli.Context, targetUser string) madmin.AddServiceAccountReq { 131 accessVal := ctx.String("access-key") 132 secretVal := ctx.String("secret-key") 133 name := ctx.String("name") 134 description := ctx.String("description") 135 policyPath := ctx.String("policy") 136 137 expDurVal := ctx.Duration("expiry-duration") 138 expVal := ctx.String("expiry") 139 140 if expVal != "" && expDurVal != 0 { 141 e := fmt.Errorf("Only one of --expiry or --expiry-duration can be specified") 142 fatalIf(probe.NewError(e), "Invalid flags.") 143 } 144 145 var exp time.Time 146 if expVal != "" { 147 location, e := time.LoadLocation("Local") 148 if e != nil { 149 fatalIf(probe.NewError(e), "Unable to parse the expiry argument.") 150 } 151 152 patternMatched := false 153 for _, format := range supportedTimeFormats { 154 t, e := time.ParseInLocation(format, expVal, location) 155 if e == nil { 156 patternMatched = true 157 exp = t 158 break 159 } 160 } 161 162 if !patternMatched { 163 e := fmt.Errorf("invalid expiry date format '%s'", expVal) 164 fatalIf(probe.NewError(e), "unable to parse the expiry argument.") 165 } 166 } else if expDurVal != 0 { 167 exp = time.Now().Add(expDurVal) 168 } else { 169 exp = time.Unix(0, 0) 170 } 171 172 var policyBytes []byte 173 if policyPath != "" { 174 // Validate the policy document and ensure it has at least when statement 175 var e error 176 policyBytes, e = os.ReadFile(policyPath) 177 fatalIf(probe.NewError(e), "Unable to open the policy document.") 178 p, e := policy.ParseConfig(bytes.NewReader(policyBytes)) 179 fatalIf(probe.NewError(e), "Unable to parse the policy document.") 180 if p.IsEmpty() { 181 fatalIf(errInvalidArgument(), "Empty policy documents are not allowed.") 182 } 183 } 184 185 accessKey, secretKey, e := generateCredentials() 186 fatalIf(probe.NewError(e), "Unable to generate credentials.") 187 188 // If access key and secret key are provided, use them instead 189 if accessVal != "" { 190 accessKey = accessVal 191 } 192 if secretVal != "" { 193 secretKey = secretVal 194 } 195 return madmin.AddServiceAccountReq{ 196 Policy: policyBytes, 197 TargetUser: targetUser, 198 AccessKey: accessKey, 199 SecretKey: secretKey, 200 Name: name, 201 Description: description, 202 Expiration: &exp, 203 } 204 }