Files
mohammad-hamid 2cd0be3cbd Update authlib version (#107939)
* update authlib version

* add latest versions

* make update-workspace

* typo

* Trigger Build

* Trigger Build
2025-07-11 14:55:52 -04:00

224 lines
6.5 KiB
Go

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.ErrNamespaceMismatch, "Check should return namespace mismatch error")
assert.ErrorIs(t, compileErr, authlib.ErrNamespaceMismatch, "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")
}
})
}
}