2023-03-28 18:39:22 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
2022-03-27 10:59:30 +00:00
|
|
|
package dataplane
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/hashicorp/go-hclog"
|
|
|
|
mock "github.com/stretchr/testify/mock"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"google.golang.org/grpc/codes"
|
|
|
|
"google.golang.org/grpc/status"
|
2022-04-05 21:10:06 +00:00
|
|
|
|
|
|
|
"github.com/hashicorp/consul/acl"
|
2022-06-17 09:24:43 +00:00
|
|
|
resolver "github.com/hashicorp/consul/acl/resolver"
|
2022-07-13 15:33:48 +00:00
|
|
|
external "github.com/hashicorp/consul/agent/grpc-external"
|
|
|
|
"github.com/hashicorp/consul/agent/grpc-external/testutils"
|
2022-09-28 16:56:59 +00:00
|
|
|
structs "github.com/hashicorp/consul/agent/structs"
|
2022-04-05 21:10:06 +00:00
|
|
|
"github.com/hashicorp/consul/proto-public/pbdataplane"
|
2022-03-27 10:59:30 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const testACLToken = "acl-token"
|
|
|
|
|
|
|
|
func TestSupportedDataplaneFeatures_Success(t *testing.T) {
|
|
|
|
// Mock the ACL Resolver to return an authorizer with `service:write`.
|
|
|
|
aclResolver := &MockACLResolver{}
|
|
|
|
aclResolver.On("ResolveTokenAndDefaultMeta", testACLToken, mock.Anything, mock.Anything).
|
2023-01-04 12:40:34 +00:00
|
|
|
Return(testutils.ACLServiceWriteAny(t), nil)
|
2022-09-28 16:56:59 +00:00
|
|
|
|
|
|
|
options := structs.QueryOptions{Token: testACLToken}
|
|
|
|
ctx, err := external.ContextWithQueryOptions(context.Background(), options)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2022-03-27 10:59:30 +00:00
|
|
|
server := NewServer(Config{
|
|
|
|
Logger: hclog.NewNullLogger(),
|
|
|
|
ACLResolver: aclResolver,
|
|
|
|
})
|
|
|
|
client := testClient(t, server)
|
2022-04-20 00:24:21 +00:00
|
|
|
resp, err := client.GetSupportedDataplaneFeatures(ctx, &pbdataplane.GetSupportedDataplaneFeaturesRequest{})
|
2022-03-27 10:59:30 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 3, len(resp.SupportedDataplaneFeatures))
|
|
|
|
|
|
|
|
for _, feature := range resp.SupportedDataplaneFeatures {
|
|
|
|
switch feature.GetFeatureName() {
|
2022-05-23 14:37:52 +00:00
|
|
|
case pbdataplane.DataplaneFeatures_DATAPLANE_FEATURES_EDGE_CERTIFICATE_MANAGEMENT:
|
2022-03-27 10:59:30 +00:00
|
|
|
require.True(t, feature.GetSupported())
|
2022-05-23 14:37:52 +00:00
|
|
|
case pbdataplane.DataplaneFeatures_DATAPLANE_FEATURES_WATCH_SERVERS:
|
2022-03-27 10:59:30 +00:00
|
|
|
require.True(t, feature.GetSupported())
|
2022-05-23 14:37:52 +00:00
|
|
|
case pbdataplane.DataplaneFeatures_DATAPLANE_FEATURES_ENVOY_BOOTSTRAP_CONFIGURATION:
|
2022-03-27 10:59:30 +00:00
|
|
|
require.True(t, feature.GetSupported())
|
|
|
|
default:
|
|
|
|
require.False(t, feature.GetSupported())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-05 16:31:18 +00:00
|
|
|
func TestSupportedDataplaneFeatures_ACLsDisabled(t *testing.T) {
|
|
|
|
aclResolver := &MockACLResolver{}
|
|
|
|
aclResolver.On("ResolveTokenAndDefaultMeta", "", mock.Anything, mock.Anything).
|
|
|
|
Return(testutils.ACLsDisabled(t), nil)
|
|
|
|
|
|
|
|
options := structs.QueryOptions{Token: ""}
|
|
|
|
ctx, err := external.ContextWithQueryOptions(context.Background(), options)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
server := NewServer(Config{
|
|
|
|
Logger: hclog.NewNullLogger(),
|
|
|
|
ACLResolver: aclResolver,
|
|
|
|
})
|
|
|
|
client := testClient(t, server)
|
|
|
|
resp, err := client.GetSupportedDataplaneFeatures(ctx, &pbdataplane.GetSupportedDataplaneFeaturesRequest{})
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 3, len(resp.SupportedDataplaneFeatures))
|
|
|
|
}
|
|
|
|
|
2023-01-04 12:40:34 +00:00
|
|
|
func TestSupportedDataplaneFeatures_InvalidACLToken(t *testing.T) {
|
2022-03-27 10:59:30 +00:00
|
|
|
// Mock the ACL resolver to return ErrNotFound.
|
|
|
|
aclResolver := &MockACLResolver{}
|
|
|
|
aclResolver.On("ResolveTokenAndDefaultMeta", mock.Anything, mock.Anything, mock.Anything).
|
2022-06-17 09:24:43 +00:00
|
|
|
Return(resolver.Result{}, acl.ErrNotFound)
|
2022-09-28 16:56:59 +00:00
|
|
|
|
|
|
|
options := structs.QueryOptions{Token: testACLToken}
|
|
|
|
ctx, err := external.ContextWithQueryOptions(context.Background(), options)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2022-03-27 10:59:30 +00:00
|
|
|
server := NewServer(Config{
|
|
|
|
Logger: hclog.NewNullLogger(),
|
|
|
|
ACLResolver: aclResolver,
|
|
|
|
})
|
|
|
|
client := testClient(t, server)
|
2022-04-20 00:24:21 +00:00
|
|
|
resp, err := client.GetSupportedDataplaneFeatures(ctx, &pbdataplane.GetSupportedDataplaneFeaturesRequest{})
|
2022-03-27 10:59:30 +00:00
|
|
|
require.Error(t, err)
|
|
|
|
require.Equal(t, codes.Unauthenticated.String(), status.Code(err).String())
|
|
|
|
require.Nil(t, resp)
|
|
|
|
}
|
|
|
|
|
2023-01-04 12:40:34 +00:00
|
|
|
func TestSupportedDataplaneFeatures_AnonymousACLToken(t *testing.T) {
|
|
|
|
// Mock the ACL resolver to return ErrNotFound.
|
2022-03-27 10:59:30 +00:00
|
|
|
aclResolver := &MockACLResolver{}
|
2023-01-04 12:40:34 +00:00
|
|
|
aclResolver.On("ResolveTokenAndDefaultMeta", mock.Anything, mock.Anything, mock.Anything).
|
|
|
|
Return(testutils.ACLAnonymous(t), nil)
|
2022-09-28 16:56:59 +00:00
|
|
|
|
|
|
|
options := structs.QueryOptions{Token: testACLToken}
|
|
|
|
ctx, err := external.ContextWithQueryOptions(context.Background(), options)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2022-03-27 10:59:30 +00:00
|
|
|
server := NewServer(Config{
|
|
|
|
Logger: hclog.NewNullLogger(),
|
|
|
|
ACLResolver: aclResolver,
|
|
|
|
})
|
|
|
|
client := testClient(t, server)
|
2022-04-20 00:24:21 +00:00
|
|
|
resp, err := client.GetSupportedDataplaneFeatures(ctx, &pbdataplane.GetSupportedDataplaneFeaturesRequest{})
|
2022-03-27 10:59:30 +00:00
|
|
|
require.Error(t, err)
|
2023-01-04 12:40:34 +00:00
|
|
|
require.Equal(t, codes.Unauthenticated.String(), status.Code(err).String())
|
2022-03-27 10:59:30 +00:00
|
|
|
require.Nil(t, resp)
|
|
|
|
}
|
2023-01-04 12:40:34 +00:00
|
|
|
|
|
|
|
func TestSupportedDataplaneFeatures_NoPermissions(t *testing.T) {
|
|
|
|
// Mock the ACL resolver to return a deny all authorizer
|
|
|
|
aclResolver := &MockACLResolver{}
|
|
|
|
aclResolver.On("ResolveTokenAndDefaultMeta", testACLToken, mock.Anything, mock.Anything).
|
|
|
|
Return(testutils.ACLNoPermissions(t), nil)
|
|
|
|
|
|
|
|
options := structs.QueryOptions{Token: testACLToken}
|
|
|
|
ctx, err := external.ContextWithQueryOptions(context.Background(), options)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
server := NewServer(Config{
|
|
|
|
Logger: hclog.NewNullLogger(),
|
|
|
|
ACLResolver: aclResolver,
|
|
|
|
})
|
|
|
|
client := testClient(t, server)
|
|
|
|
_, err = client.GetSupportedDataplaneFeatures(ctx, &pbdataplane.GetSupportedDataplaneFeaturesRequest{})
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|