2023-04-10 15:36:59 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
2022-11-28 09:51:45 +00:00
|
|
|
package command
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"flag"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/hashicorp/nomad/api"
|
|
|
|
"github.com/mitchellh/cli"
|
|
|
|
"github.com/posener/complete"
|
|
|
|
"golang.org/x/exp/slices"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Ensure ACLAuthMethodUpdateCommand satisfies the cli.Command interface.
|
|
|
|
var _ cli.Command = &ACLAuthMethodUpdateCommand{}
|
|
|
|
|
|
|
|
// ACLAuthMethodUpdateCommand implements cli.Command.
|
|
|
|
type ACLAuthMethodUpdateCommand struct {
|
|
|
|
Meta
|
|
|
|
|
|
|
|
methodType string
|
|
|
|
tokenLocality string
|
|
|
|
maxTokenTTL time.Duration
|
|
|
|
isDefault bool
|
|
|
|
config string
|
2022-12-14 12:25:40 +00:00
|
|
|
json bool
|
|
|
|
tmpl string
|
2022-11-28 09:51:45 +00:00
|
|
|
|
|
|
|
testStdin io.Reader
|
|
|
|
}
|
|
|
|
|
|
|
|
// Help satisfies the cli.Command Help function.
|
|
|
|
func (a *ACLAuthMethodUpdateCommand) Help() string {
|
|
|
|
helpText := `
|
|
|
|
Usage: nomad acl auth-method update [options] <acl_auth_method_name>
|
|
|
|
|
|
|
|
Update is used to update ACL auth methods. Use requires a management token.
|
|
|
|
|
|
|
|
General Options:
|
|
|
|
|
|
|
|
` + generalOptionsUsage(usageOptsDefault|usageOptsNoNamespace) + `
|
|
|
|
|
|
|
|
ACL Auth Method Update Options:
|
|
|
|
|
|
|
|
-type
|
2023-03-20 09:33:46 +00:00
|
|
|
Updates the type of the auth method. Supported types are 'OIDC' and 'JWT'.
|
2022-11-28 09:51:45 +00:00
|
|
|
|
|
|
|
-max-token-ttl
|
|
|
|
Updates the duration of time all tokens created by this auth method should be
|
|
|
|
valid for.
|
|
|
|
|
|
|
|
-token-locality
|
|
|
|
Updates the kind of token that this auth method should produce. This can be
|
|
|
|
either 'local' or 'global'.
|
|
|
|
|
|
|
|
-default
|
|
|
|
Specifies whether this auth method should be treated as a default one in
|
|
|
|
case no auth method is explicitly specified for a login command.
|
|
|
|
|
|
|
|
-config
|
2022-12-14 12:25:40 +00:00
|
|
|
Updates auth method configuration (in JSON format). May be prefixed with
|
|
|
|
'@' to indicate that the value is a file path to load the config from. '-'
|
|
|
|
may also be given to indicate that the config is available on stdin.
|
|
|
|
|
|
|
|
-json
|
|
|
|
Output the ACL auth-method in a JSON format.
|
|
|
|
|
|
|
|
-t
|
|
|
|
Format and display the ACL auth-method using a Go template.
|
2022-11-28 09:51:45 +00:00
|
|
|
`
|
|
|
|
|
|
|
|
return strings.TrimSpace(helpText)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *ACLAuthMethodUpdateCommand) AutocompleteFlags() complete.Flags {
|
|
|
|
return mergeAutocompleteFlags(a.Meta.AutocompleteFlags(FlagSetClient),
|
|
|
|
complete.Flags{
|
2023-03-20 09:33:46 +00:00
|
|
|
"-type": complete.PredictSet("OIDC", "JWT"),
|
2022-11-28 09:51:45 +00:00
|
|
|
"-max-token-ttl": complete.PredictAnything,
|
|
|
|
"-token-locality": complete.PredictSet("local", "global"),
|
|
|
|
"-default": complete.PredictSet("true", "false"),
|
|
|
|
"-config": complete.PredictNothing,
|
2022-12-14 12:25:40 +00:00
|
|
|
"-json": complete.PredictNothing,
|
|
|
|
"-t": complete.PredictAnything,
|
2022-11-28 09:51:45 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *ACLAuthMethodUpdateCommand) AutocompleteArgs() complete.Predictor {
|
|
|
|
return complete.PredictNothing
|
|
|
|
}
|
|
|
|
|
|
|
|
// Synopsis satisfies the cli.Command Synopsis function.
|
|
|
|
func (a *ACLAuthMethodUpdateCommand) Synopsis() string { return "Update an existing ACL auth method" }
|
|
|
|
|
|
|
|
// Name returns the name of this command.
|
|
|
|
func (*ACLAuthMethodUpdateCommand) Name() string { return "acl auth-method update" }
|
|
|
|
|
|
|
|
// Run satisfies the cli.Command Run function.
|
|
|
|
func (a *ACLAuthMethodUpdateCommand) Run(args []string) int {
|
|
|
|
|
|
|
|
flags := a.Meta.FlagSet(a.Name(), FlagSetClient)
|
|
|
|
flags.Usage = func() { a.Ui.Output(a.Help()) }
|
|
|
|
flags.StringVar(&a.methodType, "type", "", "")
|
|
|
|
flags.StringVar(&a.tokenLocality, "token-locality", "", "")
|
|
|
|
flags.DurationVar(&a.maxTokenTTL, "max-token-ttl", 0, "")
|
|
|
|
flags.StringVar(&a.config, "config", "", "")
|
|
|
|
flags.BoolVar(&a.isDefault, "default", false, "")
|
2022-12-14 12:25:40 +00:00
|
|
|
flags.BoolVar(&a.json, "json", false, "")
|
|
|
|
flags.StringVar(&a.tmpl, "t", "", "")
|
2022-11-28 09:51:45 +00:00
|
|
|
if err := flags.Parse(args); err != nil {
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that the last argument is the auth method name to delete.
|
|
|
|
if len(flags.Args()) != 1 {
|
|
|
|
a.Ui.Error("This command takes one argument: <acl_auth_method_name>")
|
|
|
|
a.Ui.Error(commandErrorText(a))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
originalMethodName := flags.Args()[0]
|
|
|
|
|
|
|
|
// Get the HTTP client.
|
|
|
|
client, err := a.Meta.Client()
|
|
|
|
if err != nil {
|
|
|
|
a.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if the method we want to update exists
|
|
|
|
originalMethod, _, err := client.ACLAuthMethods().Get(originalMethodName, nil)
|
|
|
|
if err != nil {
|
|
|
|
a.Ui.Error(fmt.Sprintf("Error when retrieving ACL auth method: %v", err))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if any command-specific flags were set
|
|
|
|
setFlags := []string{}
|
|
|
|
for _, f := range []string{"type", "token-locality", "max-token-ttl", "config", "default"} {
|
|
|
|
if flagPassed(flags, f) {
|
|
|
|
setFlags = append(setFlags, f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(setFlags) == 0 {
|
|
|
|
a.Ui.Error("Please provide at least one flag to update the ACL auth method")
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
updatedMethod := *originalMethod
|
|
|
|
|
|
|
|
if slices.Contains(setFlags, "token-locality") {
|
|
|
|
if !slices.Contains([]string{"global", "local"}, a.tokenLocality) {
|
|
|
|
a.Ui.Error("Token locality must be set to either 'local' or 'global'")
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
updatedMethod.TokenLocality = a.tokenLocality
|
|
|
|
}
|
|
|
|
|
|
|
|
if slices.Contains(setFlags, "type") {
|
2023-03-20 09:33:46 +00:00
|
|
|
if !slices.Contains([]string{"OIDC", "JWT"}, strings.ToUpper(a.methodType)) {
|
|
|
|
a.Ui.Error("ACL auth method type must be set to 'OIDC' or 'JWT'")
|
2022-11-28 09:51:45 +00:00
|
|
|
return 1
|
|
|
|
}
|
|
|
|
updatedMethod.Type = a.methodType
|
|
|
|
}
|
|
|
|
|
|
|
|
if slices.Contains(setFlags, "max-token-ttl") {
|
|
|
|
if a.maxTokenTTL < 1 {
|
|
|
|
a.Ui.Error("Max token TTL must be set to a value between min and max TTL configured for the server.")
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
updatedMethod.MaxTokenTTL = a.maxTokenTTL
|
|
|
|
}
|
|
|
|
|
|
|
|
if slices.Contains(setFlags, "default") {
|
|
|
|
updatedMethod.Default = a.isDefault
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(a.config) != 0 {
|
|
|
|
config, err := loadDataSource(a.config, a.testStdin)
|
|
|
|
if err != nil {
|
|
|
|
a.Ui.Error(fmt.Sprintf("Error loading configuration: %v", err))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
configJSON := api.ACLAuthMethodConfig{}
|
|
|
|
err = json.Unmarshal([]byte(config), &configJSON)
|
|
|
|
if err != nil {
|
|
|
|
a.Ui.Error(fmt.Sprintf("Unable to parse config: %v", err))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
updatedMethod.Config = &configJSON
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the auth method via the API.
|
2022-11-29 06:36:36 +00:00
|
|
|
method, _, err := client.ACLAuthMethods().Update(&updatedMethod, nil)
|
2022-11-28 09:51:45 +00:00
|
|
|
if err != nil {
|
|
|
|
a.Ui.Error(fmt.Sprintf("Error updating ACL auth method: %v", err))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
2022-12-14 12:25:40 +00:00
|
|
|
if a.json || len(a.tmpl) > 0 {
|
|
|
|
out, err := Format(a.json, a.tmpl, method)
|
|
|
|
if err != nil {
|
|
|
|
a.Ui.Error(err.Error())
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
a.Ui.Output(out)
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2023-01-30 10:44:26 +00:00
|
|
|
outputAuthMethod(a.Meta, method)
|
2022-11-28 09:51:45 +00:00
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
func flagPassed(flags *flag.FlagSet, name string) bool {
|
|
|
|
found := false
|
|
|
|
flags.Visit(func(f *flag.Flag) {
|
|
|
|
if f.Name == name {
|
|
|
|
found = true
|
|
|
|
}
|
|
|
|
})
|
|
|
|
return found
|
|
|
|
}
|