mirror of https://github.com/hashicorp/consul
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
229 lines
6.9 KiB
229 lines
6.9 KiB
// Copyright (c) HashiCorp, Inc. |
|
// SPDX-License-Identifier: BUSL-1.1 |
|
|
|
package acl |
|
|
|
import ( |
|
"context" |
|
"fmt" |
|
"testing" |
|
|
|
"github.com/stretchr/testify/mock" |
|
"github.com/stretchr/testify/require" |
|
"google.golang.org/grpc" |
|
"google.golang.org/grpc/codes" |
|
"google.golang.org/grpc/status" |
|
|
|
"github.com/hashicorp/go-hclog" |
|
|
|
"github.com/hashicorp/consul/acl" |
|
"github.com/hashicorp/consul/agent/consul/auth" |
|
"github.com/hashicorp/consul/agent/grpc-external/testutils" |
|
"github.com/hashicorp/consul/agent/structs" |
|
"github.com/hashicorp/consul/proto-public/pbacl" |
|
) |
|
|
|
func TestServer_Logout_Success(t *testing.T) { |
|
secretID := generateID(t) |
|
|
|
tokenWriter := NewMockTokenWriter(t) |
|
tokenWriter.On("Delete", secretID, true).Return(nil) |
|
|
|
server := NewServer(Config{ |
|
ACLsEnabled: true, |
|
InPrimaryDatacenter: true, |
|
ForwardRPC: noopForwardRPC, |
|
LocalTokensEnabled: noopLocalTokensEnabled, |
|
Logger: hclog.NewNullLogger(), |
|
NewTokenWriter: func() TokenWriter { return tokenWriter }, |
|
}) |
|
|
|
_, err := server.Logout(context.Background(), &pbacl.LogoutRequest{ |
|
Token: secretID, |
|
}) |
|
require.NoError(t, err) |
|
} |
|
|
|
func TestServer_Logout_EmptyToken(t *testing.T) { |
|
server := NewServer(Config{ |
|
ACLsEnabled: true, |
|
Logger: hclog.NewNullLogger(), |
|
}) |
|
|
|
_, err := server.Logout(context.Background(), &pbacl.LogoutRequest{ |
|
Token: "", |
|
}) |
|
require.Error(t, err) |
|
require.Equal(t, codes.InvalidArgument.String(), status.Code(err).String()) |
|
require.Contains(t, err.Error(), "token is required") |
|
} |
|
|
|
func TestServer_Logout_ACLsDisabled(t *testing.T) { |
|
server := NewServer(Config{ |
|
ACLsEnabled: false, |
|
Logger: hclog.NewNullLogger(), |
|
ValidateEnterpriseRequest: noopValidateEnterpriseRequest, |
|
ForwardRPC: noopForwardRPC, |
|
LocalTokensEnabled: noopLocalTokensEnabled, |
|
}) |
|
|
|
_, err := server.Logout(context.Background(), &pbacl.LogoutRequest{ |
|
Token: generateID(t), |
|
}) |
|
require.Error(t, err) |
|
require.Equal(t, codes.FailedPrecondition.String(), status.Code(err).String()) |
|
} |
|
|
|
func TestServer_Logout_LocalTokensDisabled(t *testing.T) { |
|
server := NewServer(Config{ |
|
ACLsEnabled: true, |
|
Logger: hclog.NewNullLogger(), |
|
ForwardRPC: noopForwardRPC, |
|
LocalTokensEnabled: func() bool { return false }, |
|
}) |
|
|
|
_, err := server.Logout(context.Background(), &pbacl.LogoutRequest{ |
|
Token: generateID(t), |
|
}) |
|
require.Error(t, err) |
|
require.Equal(t, codes.FailedPrecondition.String(), status.Code(err).String()) |
|
require.Contains(t, err.Error(), "token replication is required") |
|
} |
|
|
|
func TestServer_Logout_NoSuchToken(t *testing.T) { |
|
tokenWriter := NewMockTokenWriter(t) |
|
tokenWriter.On("Delete", mock.Anything, true).Return(acl.ErrNotFound) |
|
|
|
server := NewServer(Config{ |
|
ACLsEnabled: true, |
|
Logger: hclog.NewNullLogger(), |
|
ForwardRPC: noopForwardRPC, |
|
LocalTokensEnabled: noopLocalTokensEnabled, |
|
NewTokenWriter: func() TokenWriter { return tokenWriter }, |
|
}) |
|
|
|
_, err := server.Logout(context.Background(), &pbacl.LogoutRequest{ |
|
Token: generateID(t), |
|
}) |
|
require.NoError(t, err) |
|
} |
|
|
|
func TestServer_Logout_PermissionDenied(t *testing.T) { |
|
tokenWriter := NewMockTokenWriter(t) |
|
tokenWriter.On("Delete", mock.Anything, true).Return(acl.ErrPermissionDenied) |
|
|
|
server := NewServer(Config{ |
|
ACLsEnabled: true, |
|
InPrimaryDatacenter: true, |
|
ForwardRPC: noopForwardRPC, |
|
LocalTokensEnabled: noopLocalTokensEnabled, |
|
Logger: hclog.NewNullLogger(), |
|
NewTokenWriter: func() TokenWriter { return tokenWriter }, |
|
}) |
|
|
|
_, err := server.Logout(context.Background(), &pbacl.LogoutRequest{ |
|
Token: generateID(t), |
|
}) |
|
require.Error(t, err) |
|
require.Equal(t, codes.PermissionDenied.String(), status.Code(err).String()) |
|
} |
|
|
|
func TestServer_Logout_RPCForwarding(t *testing.T) { |
|
tokenWriter := NewMockTokenWriter(t) |
|
tokenWriter.On("Delete", mock.Anything, true).Return(nil) |
|
|
|
dc1 := NewServer(Config{ |
|
ACLsEnabled: true, |
|
Logger: hclog.NewNullLogger(), |
|
NewTokenWriter: func() TokenWriter { return tokenWriter }, |
|
ForwardRPC: noopForwardRPC, |
|
LocalTokensEnabled: func() bool { return true }, |
|
}) |
|
|
|
dc1Conn, err := grpc.Dial( |
|
testutils.RunTestServer(t, dc1).String(), |
|
//nolint:staticcheck |
|
grpc.WithInsecure(), |
|
) |
|
require.NoError(t, err) |
|
|
|
dc2 := NewServer(Config{ |
|
ACLsEnabled: true, |
|
Logger: hclog.NewNullLogger(), |
|
ForwardRPC: func(rpcInfo structs.RPCInfo, fn func(*grpc.ClientConn) error) (bool, error) { |
|
return true, fn(dc1Conn) |
|
}, |
|
}) |
|
_, err = dc2.Logout(context.Background(), &pbacl.LogoutRequest{ |
|
Token: generateID(t), |
|
}) |
|
require.NoError(t, err) |
|
} |
|
|
|
func TestServer_Logout_GlobalWritesForwardedToPrimaryDC(t *testing.T) { |
|
tokenWriter := NewMockTokenWriter(t) |
|
tokenWriter.On("Delete", mock.Anything, true).Return(nil) |
|
|
|
// This test checks that requests to delete global tokens are forwared to the |
|
// primary datacenter by: |
|
// |
|
// 1. Setting up 2 servers (1 in the primary DC, 1 in the secondary). |
|
// 2. Making a logout request to the secondary DC. |
|
// 3. Mocking TokenWriter.Delete to return ErrCannotWriteGlobalToken in the |
|
// secondary DC. |
|
// 4. Checking that the primary DC server's TokenWriter receives a call to |
|
// Delete. |
|
// 5. Capturing the forwarded request's Datacenter in the primary DC server's |
|
// ForwardRPC (to check that we overwrote the user-supplied Datacenter |
|
// field to prevent infinite forwarding loops!) |
|
var forwardedRequestDatacenter string |
|
primary := NewServer(Config{ |
|
ACLsEnabled: true, |
|
InPrimaryDatacenter: true, |
|
LocalTokensEnabled: noopLocalTokensEnabled, |
|
Logger: hclog.NewNullLogger(), |
|
NewTokenWriter: func() TokenWriter { return tokenWriter }, |
|
ForwardRPC: func(info structs.RPCInfo, _ func(*grpc.ClientConn) error) (bool, error) { |
|
forwardedRequestDatacenter = info.RequestDatacenter() |
|
return false, nil |
|
}, |
|
}) |
|
|
|
primaryConn, err := grpc.Dial( |
|
testutils.RunTestServer(t, primary).String(), |
|
//nolint:staticcheck |
|
grpc.WithInsecure(), |
|
) |
|
require.NoError(t, err) |
|
|
|
secondary := NewServer(Config{ |
|
ACLsEnabled: true, |
|
InPrimaryDatacenter: false, |
|
LocalTokensEnabled: noopLocalTokensEnabled, |
|
Logger: hclog.NewNullLogger(), |
|
PrimaryDatacenter: "primary", |
|
ForwardRPC: func(info structs.RPCInfo, fn func(*grpc.ClientConn) error) (bool, error) { |
|
dc := info.RequestDatacenter() |
|
switch dc { |
|
case "secondary": |
|
return false, nil |
|
case "primary": |
|
return true, fn(primaryConn) |
|
default: |
|
return false, fmt.Errorf("unexpected target datacenter: %s", dc) |
|
} |
|
}, |
|
NewTokenWriter: func() TokenWriter { |
|
tokenWriter := NewMockTokenWriter(t) |
|
tokenWriter.On("Delete", mock.Anything, true).Return(auth.ErrCannotWriteGlobalToken) |
|
return tokenWriter |
|
}, |
|
}) |
|
|
|
_, err = secondary.Logout(context.Background(), &pbacl.LogoutRequest{ |
|
Token: generateID(t), |
|
Datacenter: "secondary", |
|
}) |
|
require.NoError(t, err) |
|
require.Equal(t, "primary", forwardedRequestDatacenter) |
|
}
|
|
|