The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
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.
 
 
 
 
 
 
grafana/pkg/storage/unified/resource/access_test.go

223 lines
6.5 KiB

package resource
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
authlib "github.com/grafana/authlib/types"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/grafana/pkg/apimachinery/utils"
)
func TestAuthzLimitedClient_Check(t *testing.T) {
mockClient := authlib.FixedAccessClient(false)
client := NewAuthzLimitedClient(mockClient, AuthzOptions{})
tests := []struct {
group string
resource string
expected bool
}{
{"dashboard.grafana.app", "dashboards", false},
{"folder.grafana.app", "folders", false},
{"unknown.group", "unknown.resource", true},
}
for _, test := range tests {
req := authlib.CheckRequest{
Group: test.group,
Resource: test.resource,
Verb: utils.VerbGet,
Namespace: "stacks-1",
}
resp, err := client.Check(context.Background(), &identity.StaticRequester{Namespace: "stacks-1"}, req)
assert.NoError(t, err)
assert.Equal(t, test.expected, resp.Allowed)
}
}
func TestAuthzLimitedClient_Compile(t *testing.T) {
mockClient := authlib.FixedAccessClient(false)
client := NewAuthzLimitedClient(mockClient, AuthzOptions{})
tests := []struct {
group string
resource string
expected bool
}{
{"dashboard.grafana.app", "dashboards", false},
{"folder.grafana.app", "folders", false},
{"unknown.group", "unknown.resource", true},
}
for _, test := range tests {
req := authlib.ListRequest{
Group: test.group,
Resource: test.resource,
Verb: utils.VerbGet,
Namespace: "stacks-1",
}
checker, err := client.Compile(context.Background(), &identity.StaticRequester{Namespace: "stacks-1"}, req)
assert.NoError(t, err)
assert.NotNil(t, checker)
result := checker("name", "folder")
assert.Equal(t, test.expected, result)
}
}
// TestNamespaceMatching tests namespace matching in Check and Compile methods
func TestNamespaceMatching(t *testing.T) {
// Create a mock client that always returns allowed=true
mockClient := authlib.FixedAccessClient(true)
client := NewAuthzLimitedClient(mockClient, AuthzOptions{})
// Create a context with fallback disabled
ctx := context.Background()
tests := []struct {
name string
authNamespace string
reqNamespace string
expectError bool
}{
{
name: "matching namespaces",
authNamespace: "ns1",
reqNamespace: "ns1",
expectError: false,
},
{
name: "mismatched namespaces",
authNamespace: "ns1",
reqNamespace: "ns2",
expectError: true,
},
{
name: "empty request namespace",
authNamespace: "ns1",
reqNamespace: "",
expectError: true,
},
{
name: "empty auth namespace",
authNamespace: "",
reqNamespace: "ns1",
expectError: true,
},
{
name: "wildcard auth namespace",
authNamespace: "*",
reqNamespace: "ns1",
expectError: false,
},
{
name: "both empty namespaces",
authNamespace: "",
reqNamespace: "",
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Test Check method with namespace matching
checkReq := authlib.CheckRequest{
Group: "unknown.group", // Use unknown group to bypass RBAC check
Resource: "unknown.resource",
Verb: utils.VerbGet,
Namespace: tt.reqNamespace,
}
// Create a mock auth info with the specified namespace
// Test Check method
user := &identity.StaticRequester{Namespace: tt.authNamespace}
_, checkErr := client.Check(ctx, user, checkReq)
// Test Compile method
compileReq := authlib.ListRequest{
Group: "unknown.group", // Use unknown group to bypass RBAC check
Resource: "unknown.resource",
Verb: utils.VerbGet,
Namespace: tt.reqNamespace,
}
_, compileErr := client.Compile(ctx, user, compileReq)
if tt.expectError {
require.Error(t, checkErr, "Check should return error")
require.Error(t, compileErr, "Compile should return error")
assert.ErrorIs(t, checkErr, authlib.ErrNamespaceMissmatch, "Check should return namespace mismatch error")
assert.ErrorIs(t, compileErr, authlib.ErrNamespaceMissmatch, "Compile should return namespace mismatch error")
} else {
assert.NoError(t, checkErr, "Check should not return error when namespaces match")
assert.NoError(t, compileErr, "Compile should not return error when namespaces match")
}
})
}
}
// TestNamespaceMatchingFallback tests namespace matching in Check and Compile methods when fallback is used
func TestNamespaceMatchingFallback(t *testing.T) {
// Create a mock client that always returns allowed=true
mockClient := authlib.FixedAccessClient(true)
client := NewAuthzLimitedClient(mockClient, AuthzOptions{})
// Create a context with fallback disabled
ctx := context.Background()
tests := []struct {
name string
authNamespace string
reqNamespace string
expectError bool
}{
{
name: "with namespace fallback",
reqNamespace: "ns1",
expectError: false,
},
{
name: "empty request namespace with fallback",
reqNamespace: "",
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Test Check method with namespace matching
checkReq := authlib.CheckRequest{
Group: "unknown.group", // Use unknown group to bypass RBAC check
Resource: "unknown.resource",
Verb: utils.VerbGet,
Namespace: tt.reqNamespace,
}
ctx = WithFallback(ctx)
// Create a mock auth info with the specified namespace
// Test Check method
user := &identity.StaticRequester{Namespace: tt.authNamespace}
_, checkErr := client.Check(ctx, user, checkReq)
// Test Compile method
compileReq := authlib.ListRequest{
Group: "unknown.group", // Use unknown group to bypass RBAC check
Resource: "unknown.resource",
Verb: utils.VerbGet,
Namespace: tt.reqNamespace,
}
_, compileErr := client.Compile(ctx, user, compileReq)
if tt.expectError {
require.Error(t, checkErr, "Check should return error")
require.Error(t, compileErr, "Compile should return error")
assert.ErrorContains(t, checkErr, "namespace empty", "Check should return namespace mismatch error")
assert.ErrorContains(t, compileErr, "namespace empty", "Compile should return namespace mismatch error")
} else {
assert.NoError(t, checkErr, "Check should not return error when namespaces match")
assert.NoError(t, compileErr, "Compile should not return error when namespaces match")
}
})
}
}