diff --git a/agent/consul/acl_endpoint_test.go b/agent/consul/acl_endpoint_test.go index bd31232c1b..10574dc0f7 100644 --- a/agent/consul/acl_endpoint_test.go +++ b/agent/consul/acl_endpoint_test.go @@ -74,252 +74,6 @@ func TestACLEndpoint_BootstrapTokens(t *testing.T) { require.Equal(t, out.CreateIndex, out.ModifyIndex) } -func TestACLEndpoint_Apply(t *testing.T) { - if testing.Short() { - t.Skip("too slow for testing.Short") - } - - t.Parallel() - _, srv, codec := testACLServerWithConfig(t, nil, false) - waitForLeaderEstablishment(t, srv) - - arg := structs.ACLRequest{ - Datacenter: "dc1", - Op: structs.ACLSet, - ACL: structs.ACL{ - Name: "User token", - Type: structs.ACLTokenTypeClient, - }, - WriteRequest: structs.WriteRequest{Token: TestDefaultMasterToken}, - } - var out string - err := msgpackrpc.CallWithCodec(codec, "ACL.Apply", &arg, &out) - require.NoError(t, err) - id := out - - // Verify - state := srv.fsm.State() - _, s, err := state.ACLTokenGetBySecret(nil, out, nil) - require.NoError(t, err) - require.NotNil(t, s) - require.Equal(t, out, s.SecretID) - require.Equal(t, "User token", s.Description) - - // Do a delete - arg.Op = structs.ACLDelete - arg.ACL.ID = out - err = msgpackrpc.CallWithCodec(codec, "ACL.Apply", &arg, &out) - require.NoError(t, err) - - // Verify - _, s, err = state.ACLTokenGetBySecret(nil, id, nil) - require.NoError(t, err) - require.Nil(t, s) -} - -func TestACLEndpoint_Update_PurgeCache(t *testing.T) { - if testing.Short() { - t.Skip("too slow for testing.Short") - } - - t.Parallel() - _, srv, codec := testACLServerWithConfig(t, nil, false) - waitForLeaderEstablishment(t, srv) - - arg := structs.ACLRequest{ - Datacenter: "dc1", - Op: structs.ACLSet, - ACL: structs.ACL{ - Name: "User token", - Type: structs.ACLTokenTypeClient, - Rules: `key "" { policy = "read"}`, - }, - WriteRequest: structs.WriteRequest{Token: TestDefaultMasterToken}, - } - var out string - err := msgpackrpc.CallWithCodec(codec, "ACL.Apply", &arg, &out) - require.NoError(t, err) - id := out - - // Resolve - acl1, err := srv.ResolveToken(id) - require.NoError(t, err) - require.NotNil(t, acl1) - require.Equal(t, acl.Allow, acl1.KeyRead("foo", nil)) - - // Do an update - arg.ACL.ID = out - arg.ACL.Rules = `{"key": {"": {"policy": "deny"}}}` - err = msgpackrpc.CallWithCodec(codec, "ACL.Apply", &arg, &out) - require.NoError(t, err) - - // Resolve again - acl2, err := srv.ResolveToken(id) - require.NoError(t, err) - require.NotNil(t, acl2) - require.NotSame(t, acl2, acl1) - require.NotEqual(t, acl.Allow, acl2.KeyRead("foo", nil)) - - // Do a delete - arg.Op = structs.ACLDelete - arg.ACL.Rules = "" - err = msgpackrpc.CallWithCodec(codec, "ACL.Apply", &arg, &out) - require.NoError(t, err) - - // Resolve again - acl3, err := srv.ResolveToken(id) - require.True(t, acl.IsErrNotFound(err), "Error %v is not acl.ErrNotFound", err) - require.Nil(t, acl3) -} - -func TestACLEndpoint_Apply_CustomID(t *testing.T) { - if testing.Short() { - t.Skip("too slow for testing.Short") - } - - t.Parallel() - _, srv, codec := testACLServerWithConfig(t, nil, false) - waitForLeaderEstablishment(t, srv) - - arg := structs.ACLRequest{ - Datacenter: "dc1", - Op: structs.ACLSet, - ACL: structs.ACL{ - ID: "foobarbaz", // Specify custom ID, does not exist - Name: "User token", - Type: structs.ACLTokenTypeClient, - }, - WriteRequest: structs.WriteRequest{Token: TestDefaultMasterToken}, - } - var out string - err := msgpackrpc.CallWithCodec(codec, "ACL.Apply", &arg, &out) - require.NoError(t, err) - require.Equal(t, "foobarbaz", out) - - // Verify - state := srv.fsm.State() - _, s, err := state.ACLTokenGetBySecret(nil, out, nil) - require.NoError(t, err) - require.NotNil(t, s) - require.Equal(t, out, s.SecretID) - require.Equal(t, "User token", s.Description) -} - -func TestACLEndpoint_Apply_Denied(t *testing.T) { - if testing.Short() { - t.Skip("too slow for testing.Short") - } - - t.Parallel() - _, srv, codec := testACLServerWithConfig(t, nil, false) - waitForLeaderEstablishment(t, srv) - - arg := structs.ACLRequest{ - Datacenter: "dc1", - Op: structs.ACLSet, - ACL: structs.ACL{ - Name: "User token", - Type: structs.ACLTokenTypeClient, - }, - } - var out string - err := msgpackrpc.CallWithCodec(codec, "ACL.Apply", &arg, &out) - require.True(t, acl.IsErrPermissionDenied(err), "Err %v is not acl.PermissionDenied", err) -} - -func TestACLEndpoint_Apply_DeleteAnon(t *testing.T) { - if testing.Short() { - t.Skip("too slow for testing.Short") - } - - t.Parallel() - _, srv, codec := testACLServerWithConfig(t, nil, false) - waitForLeaderEstablishment(t, srv) - - arg := structs.ACLRequest{ - Datacenter: "dc1", - Op: structs.ACLDelete, - ACL: structs.ACL{ - ID: anonymousToken, - Name: "User token", - Type: structs.ACLTokenTypeClient, - }, - WriteRequest: structs.WriteRequest{Token: TestDefaultMasterToken}, - } - var out string - err := msgpackrpc.CallWithCodec(codec, "ACL.Apply", &arg, &out) - testutil.RequireErrorContains(t, err, "delete anonymous") -} - -func TestACLEndpoint_Apply_RootChange(t *testing.T) { - if testing.Short() { - t.Skip("too slow for testing.Short") - } - - t.Parallel() - _, srv, codec := testACLServerWithConfig(t, nil, false) - waitForLeaderEstablishment(t, srv) - - arg := structs.ACLRequest{ - Datacenter: "dc1", - Op: structs.ACLSet, - ACL: structs.ACL{ - ID: "manage", - Name: "User token", - Type: structs.ACLTokenTypeClient, - }, - WriteRequest: structs.WriteRequest{Token: TestDefaultMasterToken}, - } - var out string - err := msgpackrpc.CallWithCodec(codec, "ACL.Apply", &arg, &out) - testutil.RequireErrorContains(t, err, "root ACL") -} - -func TestACLEndpoint_GetPolicy(t *testing.T) { - if testing.Short() { - t.Skip("too slow for testing.Short") - } - - t.Parallel() - _, srv, codec := testACLServerWithConfig(t, nil, false) - waitForLeaderEstablishment(t, srv) - - arg := structs.ACLRequest{ - Datacenter: "dc1", - Op: structs.ACLSet, - ACL: structs.ACL{ - Name: "User token", - Type: structs.ACLTokenTypeClient, - }, - WriteRequest: structs.WriteRequest{Token: TestDefaultMasterToken}, - } - var out string - err := msgpackrpc.CallWithCodec(codec, "ACL.Apply", &arg, &out) - require.NoError(t, err) - - getR := structs.ACLPolicyResolveLegacyRequest{ - Datacenter: "dc1", - ACL: out, - } - - var acls structs.ACLPolicyResolveLegacyResponse - retry.Run(t, func(r *retry.R) { - err := msgpackrpc.CallWithCodec(codec, "ACL.GetPolicy", &getR, &acls) - - require.NoError(r, err) - require.NotNil(t, acls.Policy) - require.Equal(t, 30*time.Second, acls.TTL) - }) - - // Do a conditional lookup with etag - getR.ETag = acls.ETag - var out2 structs.ACLPolicyResolveLegacyResponse - require.NoError(t, msgpackrpc.CallWithCodec(codec, "ACL.GetPolicy", &getR, &out2)) - - require.Nil(t, out2.Policy) - require.Equal(t, 30*time.Second, out2.TTL) -} - func TestACLEndpoint_GetPolicy_Management(t *testing.T) { if testing.Short() { t.Skip("too slow for testing.Short") diff --git a/agent/consul/acl_test.go b/agent/consul/acl_test.go index c449355d2c..720fdd5f6b 100644 --- a/agent/consul/acl_test.go +++ b/agent/consul/acl_test.go @@ -9,6 +9,8 @@ import ( "testing" "time" + "github.com/hashicorp/go-uuid" + msgpackrpc "github.com/hashicorp/net-rpc-msgpackrpc" "github.com/mitchellh/copystructure" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -3771,3 +3773,80 @@ func TestACLResolver_ACLsEnabled(t *testing.T) { } } + +func TestACLResolver_ResolveTokenToIdentityAndAuthorizer_UpdatesPurgeTheCache(t *testing.T) { + if testing.Short() { + t.Skip("too slow for testing.Short") + } + + t.Parallel() + _, srv, codec := testACLServerWithConfig(t, nil, false) + waitForLeaderEstablishment(t, srv) + + reqPolicy := structs.ACLPolicySetRequest{ + Datacenter: "dc1", + Policy: structs.ACLPolicy{ + Name: "the-policy", + Rules: `key_prefix "" { policy = "read"}`, + }, + WriteRequest: structs.WriteRequest{Token: TestDefaultMasterToken}, + } + var respPolicy = structs.ACLPolicy{} + err := msgpackrpc.CallWithCodec(codec, "ACL.PolicySet", &reqPolicy, &respPolicy) + require.NoError(t, err) + + token, err := uuid.GenerateUUID() + require.NoError(t, err) + + reqToken := structs.ACLTokenSetRequest{ + Datacenter: "dc1", + ACLToken: structs.ACLToken{ + SecretID: token, + Policies: []structs.ACLTokenPolicyLink{{Name: "the-policy"}}, + }, + WriteRequest: structs.WriteRequest{Token: TestDefaultMasterToken}, + } + var respToken structs.ACLToken + err = msgpackrpc.CallWithCodec(codec, "ACL.TokenSet", &reqToken, &respToken) + require.NoError(t, err) + + runStep(t, "first resolve", func(t *testing.T) { + _, authz, err := srv.acls.ResolveTokenToIdentityAndAuthorizer(token) + require.NoError(t, err) + require.NotNil(t, authz) + require.Equal(t, acl.Allow, authz.KeyRead("foo", nil)) + }) + + runStep(t, "update the policy and resolve again", func(t *testing.T) { + reqPolicy := structs.ACLPolicySetRequest{ + Datacenter: "dc1", + Policy: structs.ACLPolicy{ + ID: respPolicy.ID, + Name: "the-policy", + Rules: `{"key_prefix": {"": {"policy": "deny"}}}`, + }, + WriteRequest: structs.WriteRequest{Token: TestDefaultMasterToken}, + } + err := msgpackrpc.CallWithCodec(codec, "ACL.PolicySet", &reqPolicy, &structs.ACLPolicy{}) + require.NoError(t, err) + + _, authz, err := srv.acls.ResolveTokenToIdentityAndAuthorizer(token) + require.NoError(t, err) + require.NotNil(t, authz) + require.Equal(t, acl.Deny, authz.KeyRead("foo", nil)) + }) + + runStep(t, "delete the token", func(t *testing.T) { + req := structs.ACLTokenDeleteRequest{ + Datacenter: "dc1", + TokenID: respToken.AccessorID, + WriteRequest: structs.WriteRequest{Token: TestDefaultMasterToken}, + } + var resp string + err := msgpackrpc.CallWithCodec(codec, "ACL.TokenDelete", &req, &resp) + require.NoError(t, err) + + _, _, err = srv.acls.ResolveTokenToIdentityAndAuthorizer(token) + require.True(t, acl.IsErrNotFound(err), "Error %v is not acl.ErrNotFound", err) + }) +} diff --git a/agent/consul/leader_test.go b/agent/consul/leader_test.go index 8d1a3d1afe..1dcaeda86e 100644 --- a/agent/consul/leader_test.go +++ b/agent/consul/leader_test.go @@ -1208,73 +1208,6 @@ func TestLeader_ACL_Initialization(t *testing.T) { } } -func TestLeader_ACLUpgrade(t *testing.T) { - if testing.Short() { - t.Skip("too slow for testing.Short") - } - - t.Parallel() - dir1, s1 := testServerWithConfig(t, func(c *Config) { - c.ACLsEnabled = true - c.PrimaryDatacenter = "dc1" - c.ACLMasterToken = "root" - }) - defer os.RemoveAll(dir1) - defer s1.Shutdown() - testrpc.WaitForTestAgent(t, s1.RPC, "dc1") - codec := rpcClient(t, s1) - defer codec.Close() - - // create a legacy management ACL - mgmt := structs.ACLRequest{ - Datacenter: "dc1", - Op: structs.ACLSet, - ACL: structs.ACL{ - Name: "Management token", - Type: structs.ACLTokenTypeManagement, - }, - WriteRequest: structs.WriteRequest{Token: "root"}, - } - var mgmt_id string - require.NoError(t, msgpackrpc.CallWithCodec(codec, "ACL.Apply", &mgmt, &mgmt_id)) - - // wait for it to be upgraded - retry.Run(t, func(t *retry.R) { - _, token, err := s1.fsm.State().ACLTokenGetBySecret(nil, mgmt_id, nil) - require.NoError(t, err) - require.NotNil(t, token) - require.NotEqual(t, "", token.AccessorID) - require.Equal(t, structs.ACLTokenTypeManagement, token.Type) - require.Len(t, token.Policies, 1) - require.Equal(t, structs.ACLPolicyGlobalManagementID, token.Policies[0].ID) - }) - - // create a legacy management ACL - client := structs.ACLRequest{ - Datacenter: "dc1", - Op: structs.ACLSet, - ACL: structs.ACL{ - Name: "Management token", - Type: structs.ACLTokenTypeClient, - Rules: `node "" { policy = "read"}`, - }, - WriteRequest: structs.WriteRequest{Token: "root"}, - } - var client_id string - require.NoError(t, msgpackrpc.CallWithCodec(codec, "ACL.Apply", &client, &client_id)) - - // wait for it to be upgraded - retry.Run(t, func(t *retry.R) { - _, token, err := s1.fsm.State().ACLTokenGetBySecret(nil, client_id, nil) - require.NoError(t, err) - require.NotNil(t, token) - require.NotEqual(t, "", token.AccessorID) - require.Len(t, token.Policies, 0) - require.Equal(t, structs.ACLTokenTypeClient, token.Type) - require.Equal(t, client.ACL.Rules, token.Rules) - }) -} - func TestLeader_ACLUpgrade_IsStickyEvenIfSerfTagsRegress(t *testing.T) { if testing.Short() { t.Skip("too slow for testing.Short")