github.com/sl1pm4t/consul@v1.4.5-0.20190325224627-74c31c540f9c/command/acl/token/clone/token_clone_test.go (about)

     1  package tokenclone
     2  
     3  import (
     4  	"os"
     5  	"regexp"
     6  	"strconv"
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/hashicorp/consul/agent"
    11  	"github.com/hashicorp/consul/api"
    12  	"github.com/hashicorp/consul/logger"
    13  	"github.com/hashicorp/consul/testrpc"
    14  	"github.com/hashicorp/consul/testutil"
    15  	"github.com/mitchellh/cli"
    16  	"github.com/stretchr/testify/require"
    17  )
    18  
    19  func parseCloneOutput(t *testing.T, output string) *api.ACLToken {
    20  	// This will only work for non-legacy tokens
    21  	re := regexp.MustCompile("Token cloned successfully.\n" +
    22  		"AccessorID:   ([a-zA-Z0-9\\-]{36})\n" +
    23  		"SecretID:     ([a-zA-Z0-9\\-]{36})\n" +
    24  		"Description:  ([^\n]*)\n" +
    25  		"Local:        (true|false)\n" +
    26  		"Create Time:  ([^\n]+)\n" +
    27  		"Policies:\n" +
    28  		"(   [a-zA-Z0-9\\-]{36} - [^\n]+\n)*")
    29  
    30  	submatches := re.FindStringSubmatch(output)
    31  	require.Lenf(t, submatches, 7, "Didn't match: %q", output)
    32  
    33  	local, err := strconv.ParseBool(submatches[4])
    34  	require.NoError(t, err)
    35  
    36  	token := &api.ACLToken{
    37  		AccessorID:  submatches[1],
    38  		SecretID:    submatches[2],
    39  		Description: submatches[3],
    40  		Local:       local,
    41  	}
    42  
    43  	if len(submatches[6]) > 0 {
    44  		policyRe := regexp.MustCompile("   ([a-zA-Z0-9\\-]{36}) - ([^\n]+)")
    45  		for _, m := range policyRe.FindAllStringSubmatch(submatches[6], -1) {
    46  			token.Policies = append(token.Policies, &api.ACLTokenPolicyLink{ID: m[1], Name: m[2]})
    47  		}
    48  	}
    49  
    50  	return token
    51  }
    52  
    53  func TestTokenCloneCommand_noTabs(t *testing.T) {
    54  	t.Parallel()
    55  
    56  	if strings.ContainsRune(New(cli.NewMockUi()).Help(), '\t') {
    57  		t.Fatal("help has tabs")
    58  	}
    59  }
    60  
    61  func TestTokenCloneCommand(t *testing.T) {
    62  	t.Parallel()
    63  	req := require.New(t)
    64  
    65  	testDir := testutil.TempDir(t, "acl")
    66  	defer os.RemoveAll(testDir)
    67  
    68  	a := agent.NewTestAgent(t, t.Name(), `
    69     primary_datacenter = "dc1"
    70     acl {
    71        enabled = true
    72        tokens {
    73           master = "root"
    74        }
    75     }`)
    76  
    77  	a.Agent.LogWriter = logger.NewLogWriter(512)
    78  
    79  	defer a.Shutdown()
    80  	testrpc.WaitForLeader(t, a.RPC, "dc1")
    81  
    82  	// Create a policy
    83  	client := a.Client()
    84  
    85  	_, _, err := client.ACL().PolicyCreate(
    86  		&api.ACLPolicy{Name: "test-policy"},
    87  		&api.WriteOptions{Token: "root"},
    88  	)
    89  	req.NoError(err)
    90  
    91  	// create a token
    92  	token, _, err := client.ACL().TokenCreate(
    93  		&api.ACLToken{Description: "test", Policies: []*api.ACLTokenPolicyLink{&api.ACLTokenPolicyLink{Name: "test-policy"}}},
    94  		&api.WriteOptions{Token: "root"},
    95  	)
    96  	req.NoError(err)
    97  
    98  	// clone with description
    99  	t.Run("Description", func(t *testing.T) {
   100  		ui := cli.NewMockUi()
   101  		cmd := New(ui)
   102  
   103  		args := []string{
   104  			"-http-addr=" + a.HTTPAddr(),
   105  			"-id=" + token.AccessorID,
   106  			"-token=root",
   107  			"-description=test cloned",
   108  		}
   109  
   110  		code := cmd.Run(args)
   111  		req.Empty(ui.ErrorWriter.String())
   112  		req.Equal(code, 0)
   113  
   114  		cloned := parseCloneOutput(t, ui.OutputWriter.String())
   115  
   116  		req.Equal("test cloned", cloned.Description)
   117  		req.Len(cloned.Policies, 1)
   118  
   119  		apiToken, _, err := client.ACL().TokenRead(
   120  			cloned.AccessorID,
   121  			&api.QueryOptions{Token: "root"},
   122  		)
   123  
   124  		req.NoError(err)
   125  		req.NotNil(apiToken)
   126  
   127  		req.Equal(cloned.AccessorID, apiToken.AccessorID)
   128  		req.Equal(cloned.SecretID, apiToken.SecretID)
   129  		req.Equal(cloned.Description, apiToken.Description)
   130  		req.Equal(cloned.Local, apiToken.Local)
   131  		req.Equal(cloned.Policies, apiToken.Policies)
   132  	})
   133  
   134  	// clone without description
   135  	t.Run("Without Description", func(t *testing.T) {
   136  		ui := cli.NewMockUi()
   137  		cmd := New(ui)
   138  
   139  		args := []string{
   140  			"-http-addr=" + a.HTTPAddr(),
   141  			"-id=" + token.AccessorID,
   142  			"-token=root",
   143  		}
   144  
   145  		code := cmd.Run(args)
   146  		req.Equal(code, 0)
   147  		req.Empty(ui.ErrorWriter.String())
   148  
   149  		cloned := parseCloneOutput(t, ui.OutputWriter.String())
   150  
   151  		req.Equal("test", cloned.Description)
   152  		req.Len(cloned.Policies, 1)
   153  
   154  		apiToken, _, err := client.ACL().TokenRead(
   155  			cloned.AccessorID,
   156  			&api.QueryOptions{Token: "root"},
   157  		)
   158  
   159  		req.NoError(err)
   160  		req.NotNil(apiToken)
   161  
   162  		req.Equal(cloned.AccessorID, apiToken.AccessorID)
   163  		req.Equal(cloned.SecretID, apiToken.SecretID)
   164  		req.Equal(cloned.Description, apiToken.Description)
   165  		req.Equal(cloned.Local, apiToken.Local)
   166  		req.Equal(cloned.Policies, apiToken.Policies)
   167  	})
   168  }