unistore: handle auth when fallback is used (#96772)
* handle auth when fallback is used * handle auth when fallback is used * add traces
This commit is contained in:
@@ -7,6 +7,10 @@ import (
|
||||
|
||||
"github.com/grafana/authlib/authz"
|
||||
"github.com/grafana/authlib/claims"
|
||||
"github.com/grafana/grafana/pkg/services/authn/grpcutils"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"go.opentelemetry.io/otel/trace/noop"
|
||||
)
|
||||
|
||||
type staticAuthzClient struct {
|
||||
@@ -38,11 +42,19 @@ type authzLimitedClient struct {
|
||||
// whitelist is a map of group to resources that are compatible with RBAC.
|
||||
whitelist groupResource
|
||||
logger *slog.Logger
|
||||
tracer trace.Tracer
|
||||
}
|
||||
|
||||
type AuthzOptions struct {
|
||||
Tracer trace.Tracer
|
||||
}
|
||||
|
||||
// NewAuthzLimitedClient creates a new authzLimitedClient.
|
||||
func NewAuthzLimitedClient(client authz.AccessChecker) authz.AccessClient {
|
||||
func NewAuthzLimitedClient(client authz.AccessChecker, opts AuthzOptions) authz.AccessClient {
|
||||
logger := slog.Default().With("logger", "limited-authz-client")
|
||||
if opts.Tracer == nil {
|
||||
opts.Tracer = noop.NewTracerProvider().Tracer("limited-authz-client")
|
||||
}
|
||||
return &authzLimitedClient{
|
||||
client: client,
|
||||
whitelist: groupResource{
|
||||
@@ -50,31 +62,57 @@ func NewAuthzLimitedClient(client authz.AccessChecker) authz.AccessClient {
|
||||
"folder.grafana.app": map[string]interface{}{"folders": nil},
|
||||
},
|
||||
logger: logger,
|
||||
tracer: opts.Tracer,
|
||||
}
|
||||
}
|
||||
|
||||
// Check implements authz.AccessClient.
|
||||
func (c authzLimitedClient) Check(ctx context.Context, id claims.AuthInfo, req authz.CheckRequest) (authz.CheckResponse, error) {
|
||||
ctx, span := c.tracer.Start(ctx, "authzLimitedClient.Check", trace.WithAttributes(
|
||||
attribute.String("group", req.Group),
|
||||
attribute.String("resource", req.Resource),
|
||||
attribute.Bool("fallback", grpcutils.FallbackUsed(ctx)),
|
||||
))
|
||||
defer span.End()
|
||||
if grpcutils.FallbackUsed(ctx) {
|
||||
c.logger.Debug("Check", "group", req.Group, "resource", req.Resource, "fallback", true, "rbac", false, "allowed", true)
|
||||
return authz.CheckResponse{Allowed: true}, nil
|
||||
}
|
||||
if !c.IsCompatibleWithRBAC(req.Group, req.Resource) {
|
||||
c.logger.Debug("Check", "group", req.Group, "resource", req.Resource, "rbac", false, "allowed", true)
|
||||
c.logger.Debug("Check", "group", req.Group, "resource", req.Resource, "fallback", false, "rbac", false, "allowed", true)
|
||||
return authz.CheckResponse{Allowed: true}, nil
|
||||
}
|
||||
t := time.Now()
|
||||
resp, err := c.client.Check(ctx, id, req)
|
||||
if err != nil {
|
||||
c.logger.Error("Check", "group", req.Group, "resource", req.Resource, "rbac", true, "error", err, "duration", time.Since(t))
|
||||
c.logger.Error("Check", "group", req.Group, "resource", req.Resource, "fallback", false, "rbac", true, "error", err, "duration", time.Since(t))
|
||||
return resp, err
|
||||
}
|
||||
c.logger.Debug("Check", "group", req.Group, "resource", req.Resource, "rbac", true, "allowed", resp.Allowed, "duration", time.Since(t))
|
||||
c.logger.Debug("Check", "group", req.Group, "resource", req.Resource, "fallback", false, "rbac", true, "allowed", resp.Allowed, "duration", time.Since(t))
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// Compile implements authz.AccessClient.
|
||||
func (c authzLimitedClient) Compile(ctx context.Context, id claims.AuthInfo, req authz.ListRequest) (authz.ItemChecker, error) {
|
||||
ctx, span := c.tracer.Start(ctx, "authzLimitedClient.Compile", trace.WithAttributes(
|
||||
attribute.String("group", req.Group),
|
||||
attribute.String("resource", req.Resource),
|
||||
))
|
||||
defer span.End()
|
||||
return func(namespace string, name, folder string) bool {
|
||||
ctx, span := c.tracer.Start(ctx, "authzLimitedClient.Compile.Check", trace.WithAttributes(
|
||||
attribute.String("group", req.Group),
|
||||
attribute.String("resource", req.Resource),
|
||||
attribute.Bool("fallback", grpcutils.FallbackUsed(ctx)),
|
||||
))
|
||||
defer span.End()
|
||||
if grpcutils.FallbackUsed(ctx) {
|
||||
c.logger.Debug("Check", "group", req.Group, "resource", req.Resource, "fallback", true, "rbac", false, "allowed", true)
|
||||
return true
|
||||
}
|
||||
// TODO: Implement For now we perform the check for each item.
|
||||
if !c.IsCompatibleWithRBAC(req.Group, req.Resource) {
|
||||
c.logger.Debug("Compile.Check", "group", req.Group, "resource", req.Resource, "namespace", namespace, "name", name, "folder", folder, "rbac", false, "allowed", true)
|
||||
c.logger.Debug("Compile.Check", "group", req.Group, "resource", req.Resource, "namespace", namespace, "name", name, "folder", folder, "fallback", false, "rbac", false, "allowed", true)
|
||||
return true
|
||||
}
|
||||
t := time.Now()
|
||||
@@ -87,10 +125,10 @@ func (c authzLimitedClient) Compile(ctx context.Context, id claims.AuthInfo, req
|
||||
Folder: folder,
|
||||
})
|
||||
if err != nil {
|
||||
c.logger.Error("Compile.Check", "group", req.Group, "resource", req.Resource, "namespace", namespace, "name", name, "folder", folder, "rbac", true, "error", err, "duration", time.Since(t))
|
||||
c.logger.Error("Compile.Check", "group", req.Group, "resource", req.Resource, "namespace", namespace, "name", name, "folder", folder, "fallback", false, "rbac", true, "error", err, "duration", time.Since(t))
|
||||
return false
|
||||
}
|
||||
c.logger.Debug("Compile.Check", "group", req.Group, "resource", req.Resource, "namespace", namespace, "name", name, "folder", folder, "rbac", true, "allowed", r.Allowed, "duration", time.Since(t))
|
||||
c.logger.Debug("Compile.Check", "group", req.Group, "resource", req.Resource, "namespace", namespace, "name", name, "folder", folder, "fallback", false, "rbac", true, "allowed", r.Allowed, "duration", time.Since(t))
|
||||
return r.Allowed
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
func TestAuthzLimitedClient_Check(t *testing.T) {
|
||||
mockClient := &staticAuthzClient{allowed: false}
|
||||
client := NewAuthzLimitedClient(mockClient)
|
||||
client := NewAuthzLimitedClient(mockClient, AuthzOptions{})
|
||||
|
||||
tests := []struct {
|
||||
group string
|
||||
@@ -35,7 +35,7 @@ func TestAuthzLimitedClient_Check(t *testing.T) {
|
||||
|
||||
func TestAuthzLimitedClient_Compile(t *testing.T) {
|
||||
mockClient := &staticAuthzClient{allowed: false}
|
||||
client := NewAuthzLimitedClient(mockClient)
|
||||
client := NewAuthzLimitedClient(mockClient, AuthzOptions{})
|
||||
|
||||
tests := []struct {
|
||||
group string
|
||||
|
||||
Reference in New Issue
Block a user