mirror of https://github.com/hashicorp/consul
acl: add DisplayName field to auth methods (#7769)
Also add a few missing acl fields in the api.pull/7725/head
parent
b5eab19183
commit
ca52ba7068
|
@ -3336,6 +3336,7 @@ func TestACLEndpoint_AuthMethodSet(t *testing.T) {
|
||||||
|
|
||||||
t.Run("Update - allow type to default", func(t *testing.T) {
|
t.Run("Update - allow type to default", func(t *testing.T) {
|
||||||
reqMethod := newAuthMethod("test")
|
reqMethod := newAuthMethod("test")
|
||||||
|
reqMethod.DisplayName = "updated display name 1"
|
||||||
reqMethod.Description = "test modified 1"
|
reqMethod.Description = "test modified 1"
|
||||||
reqMethod.Type = "" // unset
|
reqMethod.Type = "" // unset
|
||||||
|
|
||||||
|
@ -3355,12 +3356,14 @@ func TestACLEndpoint_AuthMethodSet(t *testing.T) {
|
||||||
method := methodResp.AuthMethod
|
method := methodResp.AuthMethod
|
||||||
|
|
||||||
require.Equal(t, method.Name, "test")
|
require.Equal(t, method.Name, "test")
|
||||||
|
require.Equal(t, method.DisplayName, "updated display name 1")
|
||||||
require.Equal(t, method.Description, "test modified 1")
|
require.Equal(t, method.Description, "test modified 1")
|
||||||
require.Equal(t, method.Type, "testing")
|
require.Equal(t, method.Type, "testing")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Update - specify type", func(t *testing.T) {
|
t.Run("Update - specify type", func(t *testing.T) {
|
||||||
reqMethod := newAuthMethod("test")
|
reqMethod := newAuthMethod("test")
|
||||||
|
reqMethod.DisplayName = "updated display name 2"
|
||||||
reqMethod.Description = "test modified 2"
|
reqMethod.Description = "test modified 2"
|
||||||
|
|
||||||
req := structs.ACLAuthMethodSetRequest{
|
req := structs.ACLAuthMethodSetRequest{
|
||||||
|
@ -3379,6 +3382,7 @@ func TestACLEndpoint_AuthMethodSet(t *testing.T) {
|
||||||
method := methodResp.AuthMethod
|
method := methodResp.AuthMethod
|
||||||
|
|
||||||
require.Equal(t, method.Name, "test")
|
require.Equal(t, method.Name, "test")
|
||||||
|
require.Equal(t, method.DisplayName, "updated display name 2")
|
||||||
require.Equal(t, method.Description, "test modified 2")
|
require.Equal(t, method.Description, "test modified 2")
|
||||||
require.Equal(t, method.Type, "testing")
|
require.Equal(t, method.Type, "testing")
|
||||||
})
|
})
|
||||||
|
|
|
@ -994,8 +994,9 @@ func (rules ACLBindingRules) Sort() {
|
||||||
|
|
||||||
type ACLAuthMethodListStub struct {
|
type ACLAuthMethodListStub struct {
|
||||||
Name string
|
Name string
|
||||||
Description string
|
|
||||||
Type string
|
Type string
|
||||||
|
DisplayName string `json:",omitempty"`
|
||||||
|
Description string `json:",omitempty"`
|
||||||
CreateIndex uint64
|
CreateIndex uint64
|
||||||
ModifyIndex uint64
|
ModifyIndex uint64
|
||||||
EnterpriseMeta
|
EnterpriseMeta
|
||||||
|
@ -1004,8 +1005,9 @@ type ACLAuthMethodListStub struct {
|
||||||
func (p *ACLAuthMethod) Stub() *ACLAuthMethodListStub {
|
func (p *ACLAuthMethod) Stub() *ACLAuthMethodListStub {
|
||||||
return &ACLAuthMethodListStub{
|
return &ACLAuthMethodListStub{
|
||||||
Name: p.Name,
|
Name: p.Name,
|
||||||
Description: p.Description,
|
|
||||||
Type: p.Type,
|
Type: p.Type,
|
||||||
|
DisplayName: p.DisplayName,
|
||||||
|
Description: p.Description,
|
||||||
CreateIndex: p.CreateIndex,
|
CreateIndex: p.CreateIndex,
|
||||||
ModifyIndex: p.ModifyIndex,
|
ModifyIndex: p.ModifyIndex,
|
||||||
EnterpriseMeta: p.EnterpriseMeta,
|
EnterpriseMeta: p.EnterpriseMeta,
|
||||||
|
@ -1038,8 +1040,13 @@ type ACLAuthMethod struct {
|
||||||
// Immutable once set and only settable during create.
|
// Immutable once set and only settable during create.
|
||||||
Type string
|
Type string
|
||||||
|
|
||||||
|
// DisplayName is an optional name to use instead of the Name field when
|
||||||
|
// displaying information about this auth method in any kind of user
|
||||||
|
// interface.
|
||||||
|
DisplayName string `json:",omitempty"`
|
||||||
|
|
||||||
// Description is just an optional bunch of explanatory text.
|
// Description is just an optional bunch of explanatory text.
|
||||||
Description string
|
Description string `json:",omitempty"`
|
||||||
|
|
||||||
// Configuration is arbitrary configuration for the auth method. This
|
// Configuration is arbitrary configuration for the auth method. This
|
||||||
// should only contain primitive values and containers (such as lists and
|
// should only contain primitive values and containers (such as lists and
|
||||||
|
|
|
@ -37,6 +37,7 @@ type ACLToken struct {
|
||||||
Roles []*ACLTokenRoleLink `json:",omitempty"`
|
Roles []*ACLTokenRoleLink `json:",omitempty"`
|
||||||
ServiceIdentities []*ACLServiceIdentity `json:",omitempty"`
|
ServiceIdentities []*ACLServiceIdentity `json:",omitempty"`
|
||||||
Local bool
|
Local bool
|
||||||
|
AuthMethod string `json:",omitempty"`
|
||||||
ExpirationTTL time.Duration `json:",omitempty"`
|
ExpirationTTL time.Duration `json:",omitempty"`
|
||||||
ExpirationTime *time.Time `json:",omitempty"`
|
ExpirationTime *time.Time `json:",omitempty"`
|
||||||
CreateTime time.Time `json:",omitempty"`
|
CreateTime time.Time `json:",omitempty"`
|
||||||
|
@ -60,6 +61,7 @@ type ACLTokenListEntry struct {
|
||||||
Roles []*ACLTokenRoleLink `json:",omitempty"`
|
Roles []*ACLTokenRoleLink `json:",omitempty"`
|
||||||
ServiceIdentities []*ACLServiceIdentity `json:",omitempty"`
|
ServiceIdentities []*ACLServiceIdentity `json:",omitempty"`
|
||||||
Local bool
|
Local bool
|
||||||
|
AuthMethod string `json:",omitempty"`
|
||||||
ExpirationTime *time.Time `json:",omitempty"`
|
ExpirationTime *time.Time `json:",omitempty"`
|
||||||
CreateTime time.Time
|
CreateTime time.Time
|
||||||
Hash []byte
|
Hash []byte
|
||||||
|
@ -180,7 +182,8 @@ type ACLBindingRule struct {
|
||||||
type ACLAuthMethod struct {
|
type ACLAuthMethod struct {
|
||||||
Name string
|
Name string
|
||||||
Type string
|
Type string
|
||||||
Description string
|
DisplayName string `json:",omitempty"`
|
||||||
|
Description string `json:",omitempty"`
|
||||||
|
|
||||||
// Configuration is arbitrary configuration for the auth method. This
|
// Configuration is arbitrary configuration for the auth method. This
|
||||||
// should only contain primitive values and containers (such as lists and
|
// should only contain primitive values and containers (such as lists and
|
||||||
|
@ -198,7 +201,8 @@ type ACLAuthMethod struct {
|
||||||
type ACLAuthMethodListEntry struct {
|
type ACLAuthMethodListEntry struct {
|
||||||
Name string
|
Name string
|
||||||
Type string
|
Type string
|
||||||
Description string
|
DisplayName string `json:",omitempty"`
|
||||||
|
Description string `json:",omitempty"`
|
||||||
CreateIndex uint64
|
CreateIndex uint64
|
||||||
ModifyIndex uint64
|
ModifyIndex uint64
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ type cmd struct {
|
||||||
|
|
||||||
authMethodType string
|
authMethodType string
|
||||||
name string
|
name string
|
||||||
|
displayName string
|
||||||
description string
|
description string
|
||||||
|
|
||||||
k8sHost string
|
k8sHost string
|
||||||
|
@ -62,6 +63,12 @@ func (c *cmd) init() {
|
||||||
"",
|
"",
|
||||||
"The new auth method's name. This flag is required.",
|
"The new auth method's name. This flag is required.",
|
||||||
)
|
)
|
||||||
|
c.flags.StringVar(
|
||||||
|
&c.displayName,
|
||||||
|
"display-name",
|
||||||
|
"",
|
||||||
|
"An optional name to use instead of the name when displaying this auth method in a UI.",
|
||||||
|
)
|
||||||
c.flags.StringVar(
|
c.flags.StringVar(
|
||||||
&c.description,
|
&c.description,
|
||||||
"description",
|
"description",
|
||||||
|
@ -130,6 +137,7 @@ func (c *cmd) Run(args []string) int {
|
||||||
newAuthMethod := &api.ACLAuthMethod{
|
newAuthMethod := &api.ACLAuthMethod{
|
||||||
Type: c.authMethodType,
|
Type: c.authMethodType,
|
||||||
Name: c.name,
|
Name: c.name,
|
||||||
|
DisplayName: c.displayName,
|
||||||
Description: c.description,
|
Description: c.description,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,11 +10,12 @@ import (
|
||||||
|
|
||||||
"github.com/hashicorp/consul/agent"
|
"github.com/hashicorp/consul/agent"
|
||||||
"github.com/hashicorp/consul/agent/connect"
|
"github.com/hashicorp/consul/agent/connect"
|
||||||
|
"github.com/hashicorp/consul/api"
|
||||||
"github.com/hashicorp/consul/command/acl"
|
"github.com/hashicorp/consul/command/acl"
|
||||||
"github.com/hashicorp/consul/sdk/testutil"
|
"github.com/hashicorp/consul/sdk/testutil"
|
||||||
"github.com/hashicorp/consul/testrpc"
|
"github.com/hashicorp/consul/testrpc"
|
||||||
|
"github.com/hashicorp/go-uuid"
|
||||||
"github.com/mitchellh/cli"
|
"github.com/mitchellh/cli"
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
// activate testing auth method
|
// activate testing auth method
|
||||||
|
@ -46,6 +47,7 @@ func TestAuthMethodCreateCommand(t *testing.T) {
|
||||||
|
|
||||||
defer a.Shutdown()
|
defer a.Shutdown()
|
||||||
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
||||||
|
client := a.Client()
|
||||||
|
|
||||||
t.Run("type required", func(t *testing.T) {
|
t.Run("type required", func(t *testing.T) {
|
||||||
args := []string{
|
args := []string{
|
||||||
|
@ -98,6 +100,8 @@ func TestAuthMethodCreateCommand(t *testing.T) {
|
||||||
"-token=root",
|
"-token=root",
|
||||||
"-type=testing",
|
"-type=testing",
|
||||||
"-name=test",
|
"-name=test",
|
||||||
|
"-description=desc",
|
||||||
|
"-display-name=display",
|
||||||
}
|
}
|
||||||
|
|
||||||
ui := cli.NewMockUi()
|
ui := cli.NewMockUi()
|
||||||
|
@ -106,6 +110,15 @@ func TestAuthMethodCreateCommand(t *testing.T) {
|
||||||
code := cmd.Run(args)
|
code := cmd.Run(args)
|
||||||
require.Equal(t, code, 0)
|
require.Equal(t, code, 0)
|
||||||
require.Empty(t, ui.ErrorWriter.String())
|
require.Empty(t, ui.ErrorWriter.String())
|
||||||
|
|
||||||
|
got := getTestMethod(t, client, "test")
|
||||||
|
expect := &api.ACLAuthMethod{
|
||||||
|
Name: "test",
|
||||||
|
Type: "testing",
|
||||||
|
DisplayName: "display",
|
||||||
|
Description: "desc",
|
||||||
|
}
|
||||||
|
require.Equal(t, expect, got)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,6 +139,7 @@ func TestAuthMethodCreateCommand_JSON(t *testing.T) {
|
||||||
|
|
||||||
defer a.Shutdown()
|
defer a.Shutdown()
|
||||||
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
||||||
|
client := a.Client()
|
||||||
|
|
||||||
t.Run("type required", func(t *testing.T) {
|
t.Run("type required", func(t *testing.T) {
|
||||||
args := []string{
|
args := []string{
|
||||||
|
@ -148,6 +162,8 @@ func TestAuthMethodCreateCommand_JSON(t *testing.T) {
|
||||||
"-token=root",
|
"-token=root",
|
||||||
"-type=testing",
|
"-type=testing",
|
||||||
"-name=test",
|
"-name=test",
|
||||||
|
"-description=desc",
|
||||||
|
"-display-name=display",
|
||||||
"-format=json",
|
"-format=json",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,8 +178,16 @@ func TestAuthMethodCreateCommand_JSON(t *testing.T) {
|
||||||
require.Contains(t, out, "test")
|
require.Contains(t, out, "test")
|
||||||
|
|
||||||
var jsonOutput json.RawMessage
|
var jsonOutput json.RawMessage
|
||||||
err := json.Unmarshal([]byte(out), &jsonOutput)
|
require.NoError(t, json.Unmarshal([]byte(out), &jsonOutput))
|
||||||
assert.NoError(t, err)
|
|
||||||
|
got := getTestMethod(t, client, "test")
|
||||||
|
expect := &api.ACLAuthMethod{
|
||||||
|
Name: "test",
|
||||||
|
Type: "testing",
|
||||||
|
DisplayName: "display",
|
||||||
|
Description: "desc",
|
||||||
|
}
|
||||||
|
require.Equal(t, expect, got)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,13 +208,15 @@ func TestAuthMethodCreateCommand_k8s(t *testing.T) {
|
||||||
|
|
||||||
defer a.Shutdown()
|
defer a.Shutdown()
|
||||||
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
||||||
|
client := a.Client()
|
||||||
|
|
||||||
t.Run("k8s host required", func(t *testing.T) {
|
t.Run("k8s host required", func(t *testing.T) {
|
||||||
|
name := getTestName(t)
|
||||||
args := []string{
|
args := []string{
|
||||||
"-http-addr=" + a.HTTPAddr(),
|
"-http-addr=" + a.HTTPAddr(),
|
||||||
"-token=root",
|
"-token=root",
|
||||||
"-type=kubernetes",
|
"-type=kubernetes",
|
||||||
"-name=k8s",
|
"-name", name,
|
||||||
}
|
}
|
||||||
|
|
||||||
ui := cli.NewMockUi()
|
ui := cli.NewMockUi()
|
||||||
|
@ -202,11 +228,12 @@ func TestAuthMethodCreateCommand_k8s(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("k8s ca cert required", func(t *testing.T) {
|
t.Run("k8s ca cert required", func(t *testing.T) {
|
||||||
|
name := getTestName(t)
|
||||||
args := []string{
|
args := []string{
|
||||||
"-http-addr=" + a.HTTPAddr(),
|
"-http-addr=" + a.HTTPAddr(),
|
||||||
"-token=root",
|
"-token=root",
|
||||||
"-type=kubernetes",
|
"-type=kubernetes",
|
||||||
"-name=k8s",
|
"-name", name,
|
||||||
"-kubernetes-host=https://foo.internal:8443",
|
"-kubernetes-host=https://foo.internal:8443",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,11 +248,12 @@ func TestAuthMethodCreateCommand_k8s(t *testing.T) {
|
||||||
ca := connect.TestCA(t, nil)
|
ca := connect.TestCA(t, nil)
|
||||||
|
|
||||||
t.Run("k8s jwt required", func(t *testing.T) {
|
t.Run("k8s jwt required", func(t *testing.T) {
|
||||||
|
name := getTestName(t)
|
||||||
args := []string{
|
args := []string{
|
||||||
"-http-addr=" + a.HTTPAddr(),
|
"-http-addr=" + a.HTTPAddr(),
|
||||||
"-token=root",
|
"-token=root",
|
||||||
"-type=kubernetes",
|
"-type=kubernetes",
|
||||||
"-name=k8s",
|
"-name", name,
|
||||||
"-kubernetes-host=https://foo.internal:8443",
|
"-kubernetes-host=https://foo.internal:8443",
|
||||||
"-kubernetes-ca-cert", ca.RootCert,
|
"-kubernetes-ca-cert", ca.RootCert,
|
||||||
}
|
}
|
||||||
|
@ -239,11 +267,12 @@ func TestAuthMethodCreateCommand_k8s(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("create k8s", func(t *testing.T) {
|
t.Run("create k8s", func(t *testing.T) {
|
||||||
|
name := getTestName(t)
|
||||||
args := []string{
|
args := []string{
|
||||||
"-http-addr=" + a.HTTPAddr(),
|
"-http-addr=" + a.HTTPAddr(),
|
||||||
"-token=root",
|
"-token=root",
|
||||||
"-type=kubernetes",
|
"-type=kubernetes",
|
||||||
"-name=k8s",
|
"-name", name,
|
||||||
"-kubernetes-host", "https://foo.internal:8443",
|
"-kubernetes-host", "https://foo.internal:8443",
|
||||||
"-kubernetes-ca-cert", ca.RootCert,
|
"-kubernetes-ca-cert", ca.RootCert,
|
||||||
"-kubernetes-service-account-jwt", acl.TestKubernetesJWT_A,
|
"-kubernetes-service-account-jwt", acl.TestKubernetesJWT_A,
|
||||||
|
@ -255,17 +284,30 @@ func TestAuthMethodCreateCommand_k8s(t *testing.T) {
|
||||||
code := cmd.Run(args)
|
code := cmd.Run(args)
|
||||||
require.Equal(t, code, 0)
|
require.Equal(t, code, 0)
|
||||||
require.Empty(t, ui.ErrorWriter.String())
|
require.Empty(t, ui.ErrorWriter.String())
|
||||||
|
|
||||||
|
got := getTestMethod(t, client, name)
|
||||||
|
expect := &api.ACLAuthMethod{
|
||||||
|
Name: name,
|
||||||
|
Type: "kubernetes",
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"Host": "https://foo.internal:8443",
|
||||||
|
"CACert": ca.RootCert,
|
||||||
|
"ServiceAccountJWT": acl.TestKubernetesJWT_A,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
require.Equal(t, expect, got)
|
||||||
})
|
})
|
||||||
|
|
||||||
caFile := filepath.Join(testDir, "ca.crt")
|
caFile := filepath.Join(testDir, "ca.crt")
|
||||||
require.NoError(t, ioutil.WriteFile(caFile, []byte(ca.RootCert), 0600))
|
require.NoError(t, ioutil.WriteFile(caFile, []byte(ca.RootCert), 0600))
|
||||||
|
|
||||||
t.Run("create k8s with cert file", func(t *testing.T) {
|
t.Run("create k8s with cert file", func(t *testing.T) {
|
||||||
|
name := getTestName(t)
|
||||||
args := []string{
|
args := []string{
|
||||||
"-http-addr=" + a.HTTPAddr(),
|
"-http-addr=" + a.HTTPAddr(),
|
||||||
"-token=root",
|
"-token=root",
|
||||||
"-type=kubernetes",
|
"-type=kubernetes",
|
||||||
"-name=k8s",
|
"-name", name,
|
||||||
"-kubernetes-host", "https://foo.internal:8443",
|
"-kubernetes-host", "https://foo.internal:8443",
|
||||||
"-kubernetes-ca-cert", "@" + caFile,
|
"-kubernetes-ca-cert", "@" + caFile,
|
||||||
"-kubernetes-service-account-jwt", acl.TestKubernetesJWT_A,
|
"-kubernetes-service-account-jwt", acl.TestKubernetesJWT_A,
|
||||||
|
@ -277,5 +319,42 @@ func TestAuthMethodCreateCommand_k8s(t *testing.T) {
|
||||||
code := cmd.Run(args)
|
code := cmd.Run(args)
|
||||||
require.Equal(t, code, 0)
|
require.Equal(t, code, 0)
|
||||||
require.Empty(t, ui.ErrorWriter.String())
|
require.Empty(t, ui.ErrorWriter.String())
|
||||||
|
|
||||||
|
got := getTestMethod(t, client, name)
|
||||||
|
expect := &api.ACLAuthMethod{
|
||||||
|
Name: name,
|
||||||
|
Type: "kubernetes",
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"Host": "https://foo.internal:8443",
|
||||||
|
"CACert": ca.RootCert,
|
||||||
|
"ServiceAccountJWT": acl.TestKubernetesJWT_A,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
require.Equal(t, expect, got)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getTestMethod(t *testing.T, client *api.Client, methodName string) *api.ACLAuthMethod {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
method, _, err := client.ACL().AuthMethodRead(
|
||||||
|
methodName,
|
||||||
|
&api.QueryOptions{Token: "root"},
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, method)
|
||||||
|
|
||||||
|
// zero these out since we don't really care
|
||||||
|
method.CreateIndex = 0
|
||||||
|
method.ModifyIndex = 0
|
||||||
|
|
||||||
|
return method
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTestName(t *testing.T) string {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
id, err := uuid.GenerateUUID()
|
||||||
|
require.NoError(t, err)
|
||||||
|
return "test-" + id
|
||||||
|
}
|
||||||
|
|
|
@ -54,6 +54,9 @@ func (f *prettyFormatter) FormatAuthMethod(method *api.ACLAuthMethod) (string, e
|
||||||
if method.Namespace != "" {
|
if method.Namespace != "" {
|
||||||
buffer.WriteString(fmt.Sprintf("Namespace: %s\n", method.Namespace))
|
buffer.WriteString(fmt.Sprintf("Namespace: %s\n", method.Namespace))
|
||||||
}
|
}
|
||||||
|
if method.DisplayName != "" {
|
||||||
|
buffer.WriteString(fmt.Sprintf("DisplayName: %s\n", method.DisplayName))
|
||||||
|
}
|
||||||
buffer.WriteString(fmt.Sprintf("Description: %s\n", method.Description))
|
buffer.WriteString(fmt.Sprintf("Description: %s\n", method.Description))
|
||||||
if f.showMeta {
|
if f.showMeta {
|
||||||
buffer.WriteString(fmt.Sprintf("Create Index: %d\n", method.CreateIndex))
|
buffer.WriteString(fmt.Sprintf("Create Index: %d\n", method.CreateIndex))
|
||||||
|
@ -87,6 +90,9 @@ func (f *prettyFormatter) formatAuthMethodListEntry(method *api.ACLAuthMethodLis
|
||||||
if method.Namespace != "" {
|
if method.Namespace != "" {
|
||||||
buffer.WriteString(fmt.Sprintf(" Namespace: %s\n", method.Namespace))
|
buffer.WriteString(fmt.Sprintf(" Namespace: %s\n", method.Namespace))
|
||||||
}
|
}
|
||||||
|
if method.DisplayName != "" {
|
||||||
|
buffer.WriteString(fmt.Sprintf(" DisplayName: %s\n", method.DisplayName))
|
||||||
|
}
|
||||||
buffer.WriteString(fmt.Sprintf(" Description: %s\n", method.Description))
|
buffer.WriteString(fmt.Sprintf(" Description: %s\n", method.Description))
|
||||||
if f.showMeta {
|
if f.showMeta {
|
||||||
buffer.WriteString(fmt.Sprintf(" Create Index: %d\n", method.CreateIndex))
|
buffer.WriteString(fmt.Sprintf(" Create Index: %d\n", method.CreateIndex))
|
||||||
|
|
|
@ -27,6 +27,7 @@ type cmd struct {
|
||||||
|
|
||||||
name string
|
name string
|
||||||
|
|
||||||
|
displayName string
|
||||||
description string
|
description string
|
||||||
|
|
||||||
k8sHost string
|
k8sHost string
|
||||||
|
@ -58,6 +59,13 @@ func (c *cmd) init() {
|
||||||
"The auth method name.",
|
"The auth method name.",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
c.flags.StringVar(
|
||||||
|
&c.displayName,
|
||||||
|
"display-name",
|
||||||
|
"",
|
||||||
|
"An optional name to use instead of the name when displaying this auth method in a UI.",
|
||||||
|
)
|
||||||
|
|
||||||
c.flags.StringVar(
|
c.flags.StringVar(
|
||||||
&c.description,
|
&c.description,
|
||||||
"description",
|
"description",
|
||||||
|
@ -147,6 +155,7 @@ func (c *cmd) Run(args []string) int {
|
||||||
method = &api.ACLAuthMethod{
|
method = &api.ACLAuthMethod{
|
||||||
Name: currentAuthMethod.Name,
|
Name: currentAuthMethod.Name,
|
||||||
Type: currentAuthMethod.Type,
|
Type: currentAuthMethod.Type,
|
||||||
|
DisplayName: c.displayName,
|
||||||
Description: c.description,
|
Description: c.description,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,6 +181,9 @@ func (c *cmd) Run(args []string) int {
|
||||||
methodCopy := *currentAuthMethod
|
methodCopy := *currentAuthMethod
|
||||||
method = &methodCopy
|
method = &methodCopy
|
||||||
|
|
||||||
|
if c.displayName != "" {
|
||||||
|
method.DisplayName = c.displayName
|
||||||
|
}
|
||||||
if c.description != "" {
|
if c.description != "" {
|
||||||
method.Description = c.description
|
method.Description = c.description
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@ import (
|
||||||
"github.com/hashicorp/consul/testrpc"
|
"github.com/hashicorp/consul/testrpc"
|
||||||
"github.com/hashicorp/go-uuid"
|
"github.com/hashicorp/go-uuid"
|
||||||
"github.com/mitchellh/cli"
|
"github.com/mitchellh/cli"
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
// activate testing auth method
|
// activate testing auth method
|
||||||
|
@ -66,10 +65,11 @@ func TestAuthMethodUpdateCommand(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("update nonexistent method", func(t *testing.T) {
|
t.Run("update nonexistent method", func(t *testing.T) {
|
||||||
|
name := getTestName(t)
|
||||||
args := []string{
|
args := []string{
|
||||||
"-http-addr=" + a.HTTPAddr(),
|
"-http-addr=" + a.HTTPAddr(),
|
||||||
"-token=root",
|
"-token=root",
|
||||||
"-name=test",
|
"-name", name,
|
||||||
}
|
}
|
||||||
|
|
||||||
ui := cli.NewMockUi()
|
ui := cli.NewMockUi()
|
||||||
|
@ -106,6 +106,7 @@ func TestAuthMethodUpdateCommand(t *testing.T) {
|
||||||
"-http-addr=" + a.HTTPAddr(),
|
"-http-addr=" + a.HTTPAddr(),
|
||||||
"-token=root",
|
"-token=root",
|
||||||
"-name=" + name,
|
"-name=" + name,
|
||||||
|
"-display-name", "updated display",
|
||||||
"-description", "updated description",
|
"-description", "updated description",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,13 +117,15 @@ func TestAuthMethodUpdateCommand(t *testing.T) {
|
||||||
require.Equal(t, code, 0)
|
require.Equal(t, code, 0)
|
||||||
require.Empty(t, ui.ErrorWriter.String())
|
require.Empty(t, ui.ErrorWriter.String())
|
||||||
|
|
||||||
method, _, err := client.ACL().AuthMethodRead(
|
got := getTestMethod(t, client, name)
|
||||||
name,
|
expect := &api.ACLAuthMethod{
|
||||||
&api.QueryOptions{Token: "root"},
|
Name: name,
|
||||||
)
|
Type: "testing",
|
||||||
require.NoError(t, err)
|
DisplayName: "updated display",
|
||||||
require.NotNil(t, method)
|
Description: "updated description",
|
||||||
require.Equal(t, "updated description", method.Description)
|
Config: map[string]interface{}{},
|
||||||
|
}
|
||||||
|
require.Equal(t, expect, got)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,6 +190,7 @@ func TestAuthMethodUpdateCommand_JSON(t *testing.T) {
|
||||||
"-http-addr=" + a.HTTPAddr(),
|
"-http-addr=" + a.HTTPAddr(),
|
||||||
"-token=root",
|
"-token=root",
|
||||||
"-name=" + name,
|
"-name=" + name,
|
||||||
|
"-display-name", "updated display",
|
||||||
"-description", "updated description",
|
"-description", "updated description",
|
||||||
"-format=json",
|
"-format=json",
|
||||||
}
|
}
|
||||||
|
@ -195,22 +199,23 @@ func TestAuthMethodUpdateCommand_JSON(t *testing.T) {
|
||||||
cmd := New(ui)
|
cmd := New(ui)
|
||||||
|
|
||||||
code := cmd.Run(args)
|
code := cmd.Run(args)
|
||||||
|
output := ui.OutputWriter.String()
|
||||||
|
|
||||||
require.Equal(t, code, 0)
|
require.Equal(t, code, 0)
|
||||||
require.Empty(t, ui.ErrorWriter.String())
|
require.Empty(t, ui.ErrorWriter.String())
|
||||||
|
|
||||||
method, _, err := client.ACL().AuthMethodRead(
|
|
||||||
name,
|
|
||||||
&api.QueryOptions{Token: "root"},
|
|
||||||
)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.NotNil(t, method)
|
|
||||||
require.Equal(t, "updated description", method.Description)
|
|
||||||
|
|
||||||
output := ui.OutputWriter.String()
|
|
||||||
|
|
||||||
var jsonOutput json.RawMessage
|
var jsonOutput json.RawMessage
|
||||||
err = json.Unmarshal([]byte(output), &jsonOutput)
|
require.NoError(t, json.Unmarshal([]byte(output), &jsonOutput))
|
||||||
assert.NoError(t, err)
|
|
||||||
|
got := getTestMethod(t, client, name)
|
||||||
|
expect := &api.ACLAuthMethod{
|
||||||
|
Name: name,
|
||||||
|
Type: "testing",
|
||||||
|
DisplayName: "updated display",
|
||||||
|
Description: "updated description",
|
||||||
|
Config: map[string]interface{}{},
|
||||||
|
}
|
||||||
|
require.Equal(t, expect, got)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,11 +255,12 @@ func TestAuthMethodUpdateCommand_noMerge(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("update nonexistent method", func(t *testing.T) {
|
t.Run("update nonexistent method", func(t *testing.T) {
|
||||||
|
name := getTestName(t)
|
||||||
args := []string{
|
args := []string{
|
||||||
"-http-addr=" + a.HTTPAddr(),
|
"-http-addr=" + a.HTTPAddr(),
|
||||||
"-token=root",
|
"-token=root",
|
||||||
"-no-merge",
|
"-no-merge",
|
||||||
"-name=test",
|
"-name", name,
|
||||||
}
|
}
|
||||||
|
|
||||||
ui := cli.NewMockUi()
|
ui := cli.NewMockUi()
|
||||||
|
@ -292,6 +298,7 @@ func TestAuthMethodUpdateCommand_noMerge(t *testing.T) {
|
||||||
"-token=root",
|
"-token=root",
|
||||||
"-no-merge",
|
"-no-merge",
|
||||||
"-name=" + name,
|
"-name=" + name,
|
||||||
|
"-display-name", "updated display",
|
||||||
"-description", "updated description",
|
"-description", "updated description",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,13 +309,14 @@ func TestAuthMethodUpdateCommand_noMerge(t *testing.T) {
|
||||||
require.Equal(t, code, 0, "err: %s", ui.ErrorWriter.String())
|
require.Equal(t, code, 0, "err: %s", ui.ErrorWriter.String())
|
||||||
require.Empty(t, ui.ErrorWriter.String())
|
require.Empty(t, ui.ErrorWriter.String())
|
||||||
|
|
||||||
method, _, err := client.ACL().AuthMethodRead(
|
got := getTestMethod(t, client, name)
|
||||||
name,
|
expect := &api.ACLAuthMethod{
|
||||||
&api.QueryOptions{Token: "root"},
|
Name: name,
|
||||||
)
|
Type: "testing",
|
||||||
require.NoError(t, err)
|
DisplayName: "updated display",
|
||||||
require.NotNil(t, method)
|
Description: "updated description",
|
||||||
require.Equal(t, "updated description", method.Description)
|
}
|
||||||
|
require.Equal(t, expect, got)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,6 +374,7 @@ func TestAuthMethodUpdateCommand_k8s(t *testing.T) {
|
||||||
"-http-addr=" + a.HTTPAddr(),
|
"-http-addr=" + a.HTTPAddr(),
|
||||||
"-token=root",
|
"-token=root",
|
||||||
"-name=" + name,
|
"-name=" + name,
|
||||||
|
"-display-name", "updated display",
|
||||||
"-description", "updated description",
|
"-description", "updated description",
|
||||||
"-kubernetes-host", "https://foo-new.internal:8443",
|
"-kubernetes-host", "https://foo-new.internal:8443",
|
||||||
"-kubernetes-ca-cert", ca2.RootCert,
|
"-kubernetes-ca-cert", ca2.RootCert,
|
||||||
|
@ -379,15 +388,22 @@ func TestAuthMethodUpdateCommand_k8s(t *testing.T) {
|
||||||
require.Equal(t, code, 0)
|
require.Equal(t, code, 0)
|
||||||
require.Empty(t, ui.ErrorWriter.String())
|
require.Empty(t, ui.ErrorWriter.String())
|
||||||
|
|
||||||
method, _, err := client.ACL().AuthMethodRead(
|
got := getTestMethod(t, client, name)
|
||||||
name,
|
expect := &api.ACLAuthMethod{
|
||||||
&api.QueryOptions{Token: "root"},
|
Name: name,
|
||||||
)
|
Type: "kubernetes",
|
||||||
require.NoError(t, err)
|
DisplayName: "updated display",
|
||||||
require.NotNil(t, method)
|
Description: "updated description",
|
||||||
require.Equal(t, "updated description", method.Description)
|
Config: map[string]interface{}{
|
||||||
|
"Host": "https://foo-new.internal:8443",
|
||||||
|
"CACert": ca2.RootCert,
|
||||||
|
"ServiceAccountJWT": acl.TestKubernetesJWT_B,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
require.Equal(t, expect, got)
|
||||||
|
|
||||||
config, err := api.ParseKubernetesAuthMethodConfig(method.Config)
|
// also just double check our convenience parsing
|
||||||
|
config, err := api.ParseKubernetesAuthMethodConfig(got.Config)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, "https://foo-new.internal:8443", config.Host)
|
require.Equal(t, "https://foo-new.internal:8443", config.Host)
|
||||||
require.Equal(t, ca2.RootCert, config.CACert)
|
require.Equal(t, ca2.RootCert, config.CACert)
|
||||||
|
@ -726,3 +742,28 @@ func TestAuthMethodUpdateCommand_k8s_noMerge(t *testing.T) {
|
||||||
require.Equal(t, acl.TestKubernetesJWT_B, config.ServiceAccountJWT)
|
require.Equal(t, acl.TestKubernetesJWT_B, config.ServiceAccountJWT)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getTestMethod(t *testing.T, client *api.Client, methodName string) *api.ACLAuthMethod {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
method, _, err := client.ACL().AuthMethodRead(
|
||||||
|
methodName,
|
||||||
|
&api.QueryOptions{Token: "root"},
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, method)
|
||||||
|
|
||||||
|
// zero these out since we don't really care
|
||||||
|
method.CreateIndex = 0
|
||||||
|
method.ModifyIndex = 0
|
||||||
|
|
||||||
|
return method
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTestName(t *testing.T) string {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
id, err := uuid.GenerateUUID()
|
||||||
|
require.NoError(t, err)
|
||||||
|
return "test-" + id
|
||||||
|
}
|
||||||
|
|
|
@ -57,6 +57,9 @@ func (f *prettyFormatter) FormatToken(token *api.ACLToken) (string, error) {
|
||||||
}
|
}
|
||||||
buffer.WriteString(fmt.Sprintf("Description: %s\n", token.Description))
|
buffer.WriteString(fmt.Sprintf("Description: %s\n", token.Description))
|
||||||
buffer.WriteString(fmt.Sprintf("Local: %t\n", token.Local))
|
buffer.WriteString(fmt.Sprintf("Local: %t\n", token.Local))
|
||||||
|
if token.AuthMethod != "" {
|
||||||
|
buffer.WriteString(fmt.Sprintf("Auth Method: %s\n", token.AuthMethod))
|
||||||
|
}
|
||||||
buffer.WriteString(fmt.Sprintf("Create Time: %v\n", token.CreateTime))
|
buffer.WriteString(fmt.Sprintf("Create Time: %v\n", token.CreateTime))
|
||||||
if token.ExpirationTime != nil && !token.ExpirationTime.IsZero() {
|
if token.ExpirationTime != nil && !token.ExpirationTime.IsZero() {
|
||||||
buffer.WriteString(fmt.Sprintf("Expiration Time: %v\n", *token.ExpirationTime))
|
buffer.WriteString(fmt.Sprintf("Expiration Time: %v\n", *token.ExpirationTime))
|
||||||
|
@ -121,6 +124,9 @@ func (f *prettyFormatter) formatTokenListEntry(token *api.ACLTokenListEntry) str
|
||||||
}
|
}
|
||||||
buffer.WriteString(fmt.Sprintf("Description: %s\n", token.Description))
|
buffer.WriteString(fmt.Sprintf("Description: %s\n", token.Description))
|
||||||
buffer.WriteString(fmt.Sprintf("Local: %t\n", token.Local))
|
buffer.WriteString(fmt.Sprintf("Local: %t\n", token.Local))
|
||||||
|
if token.AuthMethod != "" {
|
||||||
|
buffer.WriteString(fmt.Sprintf("Auth Method: %s\n", token.AuthMethod))
|
||||||
|
}
|
||||||
buffer.WriteString(fmt.Sprintf("Create Time: %v\n", token.CreateTime))
|
buffer.WriteString(fmt.Sprintf("Create Time: %v\n", token.CreateTime))
|
||||||
if token.ExpirationTime != nil && !token.ExpirationTime.IsZero() {
|
if token.ExpirationTime != nil && !token.ExpirationTime.IsZero() {
|
||||||
buffer.WriteString(fmt.Sprintf("Expiration Time: %v\n", *token.ExpirationTime))
|
buffer.WriteString(fmt.Sprintf("Expiration Time: %v\n", *token.ExpirationTime))
|
||||||
|
|
|
@ -40,6 +40,7 @@ The table below shows this endpoint's support for
|
||||||
- `Name` `(string: <required>)` - Specifies a name for the ACL auth method. The
|
- `Name` `(string: <required>)` - Specifies a name for the ACL auth method. The
|
||||||
name can contain alphanumeric characters, dashes `-`, and underscores `_`.
|
name can contain alphanumeric characters, dashes `-`, and underscores `_`.
|
||||||
This field is immutable and must be unique.
|
This field is immutable and must be unique.
|
||||||
|
|
||||||
- `Type` `(string: <required>)` - The type of auth method being configured.
|
- `Type` `(string: <required>)` - The type of auth method being configured.
|
||||||
The only allowed value in Consul 1.5.0 is `"kubernetes"`. This field is
|
The only allowed value in Consul 1.5.0 is `"kubernetes"`. This field is
|
||||||
immutable.
|
immutable.
|
||||||
|
@ -47,6 +48,9 @@ The table below shows this endpoint's support for
|
||||||
- `Description` `(string: "")` - Free form human readable description of the
|
- `Description` `(string: "")` - Free form human readable description of the
|
||||||
auth method.
|
auth method.
|
||||||
|
|
||||||
|
- `DisplayName` `(string: "")` - An optional name to use instead of the `Name`
|
||||||
|
field when displaying information about this auth method. Added in Consul 1.8.0.
|
||||||
|
|
||||||
- `Config` `(map[string]string: <required>)` - The raw configuration to use for
|
- `Config` `(map[string]string: <required>)` - The raw configuration to use for
|
||||||
the chosen auth method. Contents will vary depending upon the type chosen.
|
the chosen auth method. Contents will vary depending upon the type chosen.
|
||||||
For more information on configuring specific auth method types, see the [auth
|
For more information on configuring specific auth method types, see the [auth
|
||||||
|
@ -184,6 +188,9 @@ The table below shows this endpoint's support for
|
||||||
- `Description` `(string: "")` - Free form human readable description of the
|
- `Description` `(string: "")` - Free form human readable description of the
|
||||||
auth method.
|
auth method.
|
||||||
|
|
||||||
|
- `DisplayName` `(string: "")` - An optional name to use instead of the `Name`
|
||||||
|
field when displaying information about this auth method. Added in Consul 1.8.0.
|
||||||
|
|
||||||
- `Config` `(map[string]string: <required>)` - The raw configuration to use for
|
- `Config` `(map[string]string: <required>)` - The raw configuration to use for
|
||||||
the chosen auth method. Contents will vary depending upon the type chosen.
|
the chosen auth method. Contents will vary depending upon the type chosen.
|
||||||
For more information on configuring specific auth method types, see the [auth
|
For more information on configuring specific auth method types, see the [auth
|
||||||
|
|
Loading…
Reference in New Issue