diff --git a/pkg/storage/unified/resource/grpc/authenticator.go b/pkg/storage/unified/resource/grpc/authenticator.go index 6c5f2b19dd1..dbb8257feb4 100644 --- a/pkg/storage/unified/resource/grpc/authenticator.go +++ b/pkg/storage/unified/resource/grpc/authenticator.go @@ -2,16 +2,17 @@ package grpc import ( "context" - "fmt" "strconv" "google.golang.org/grpc" + "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" - "github.com/grafana/authlib/authn" authClaims "github.com/grafana/authlib/claims" "github.com/grafana/grafana/pkg/apimachinery/identity" + "github.com/grafana/grafana/pkg/infra/tracing" ) const ( @@ -27,10 +28,13 @@ const ( // var _ interceptors.Authenticator = (*Authenticator)(nil) type Authenticator struct { - IDTokenVerifier authn.Verifier[authn.IDTokenClaims] + Tracer tracing.Tracer } func (f *Authenticator) Authenticate(ctx context.Context) (context.Context, error) { + ctx, span := f.Tracer.Start(ctx, "legacy.grpc.Authenticator.Authenticate") + defer span.End() + r, err := identity.GetRequester(ctx) if err == nil && r != nil { return ctx, nil // noop, requester exists @@ -38,16 +42,19 @@ func (f *Authenticator) Authenticate(ctx context.Context) (context.Context, erro md, ok := metadata.FromIncomingContext(ctx) if !ok { - return nil, fmt.Errorf("no metadata found") + err := status.Error(codes.Unauthenticated, "no metadata found in grpc context") + span.RecordError(err) + return nil, err } - user, err := f.decodeMetadata(ctx, md) + user, err := f.decodeMetadata(md) if err != nil { + span.RecordError(err) return nil, err } return identity.WithRequester(ctx, user), nil } -func (f *Authenticator) decodeMetadata(ctx context.Context, meta metadata.MD) (identity.Requester, error) { +func (f *Authenticator) decodeMetadata(meta metadata.MD) (identity.Requester, error) { // Avoid NPE/panic with getting keys getter := func(key string) string { v := meta.Get(key) @@ -57,20 +64,10 @@ func (f *Authenticator) decodeMetadata(ctx context.Context, meta metadata.MD) (i return "" } - // First try the token - token := getter(mdToken) - if token != "" && f.IDTokenVerifier != nil { - claims, err := f.IDTokenVerifier.Verify(ctx, token) - if err != nil { - return nil, err - } - fmt.Printf("TODO, convert CLAIMS to an identity %+v\n", claims) - } - user := &identity.StaticRequester{} user.Login = getter(mdLogin) if user.Login == "" { - return nil, fmt.Errorf("no login found in grpc metadata") + return nil, status.Error(codes.Unauthenticated, "no login found in grpc metadata") } // The namespaced versions have a "-" in the key @@ -80,34 +77,34 @@ func (f *Authenticator) decodeMetadata(ctx context.Context, meta metadata.MD) (i user.Type = authClaims.TypeUser user.UserID, err = strconv.ParseInt(getter("grafana-userid"), 10, 64) if err != nil { - return nil, fmt.Errorf("invalid user id: %w", err) + return nil, status.Error(codes.Unauthenticated, "invalid user id") } user.OrgID, err = strconv.ParseInt(getter("grafana-orgid"), 10, 64) if err != nil { - return nil, fmt.Errorf("invalid org id: %w", err) + return nil, status.Error(codes.Unauthenticated, "invalid org id") } return user, nil } typ, id, err := authClaims.ParseTypeID(getter(mdUserID)) if err != nil { - return nil, fmt.Errorf("invalid user id: %w", err) + return nil, status.Error(codes.Unauthenticated, "invalid user id") } user.Type = typ user.UserID, err = strconv.ParseInt(id, 10, 64) if err != nil { - return nil, fmt.Errorf("invalid user id: %w", err) + return nil, status.Error(codes.Unauthenticated, "invalid user id") } - _, id, err = authClaims.ParseTypeID(getter(mdUserUID)) + _, uid, err := authClaims.ParseTypeID(getter(mdUserUID)) if err != nil { - return nil, fmt.Errorf("invalid user id: %w", err) + return nil, status.Error(codes.Unauthenticated, "invalid user uid") } - user.UserUID = id + user.UserUID = uid user.OrgID, err = strconv.ParseInt(getter(mdOrgID), 10, 64) if err != nil { - return nil, fmt.Errorf("invalid org id: %w", err) + return nil, status.Error(codes.Unauthenticated, "invalid org id") } user.OrgRole = identity.RoleType(getter(mdOrgRole)) return user, nil diff --git a/pkg/storage/unified/resource/grpc/authenticator_test.go b/pkg/storage/unified/resource/grpc/authenticator_test.go index 674d846c486..c89a19c6dd2 100644 --- a/pkg/storage/unified/resource/grpc/authenticator_test.go +++ b/pkg/storage/unified/resource/grpc/authenticator_test.go @@ -1,13 +1,13 @@ package grpc import ( - "context" "testing" "github.com/stretchr/testify/require" "github.com/grafana/authlib/claims" "github.com/grafana/grafana/pkg/apimachinery/identity" + "github.com/grafana/grafana/pkg/infra/tracing" ) func TestBasicEncodeDecode(t *testing.T) { @@ -20,10 +20,10 @@ func TestBasicEncodeDecode(t *testing.T) { OrgRole: identity.RoleAdmin, } - auth := &Authenticator{} + auth := &Authenticator{Tracer: tracing.NewNoopTracerService()} md := encodeIdentityInMetadata(before) - after, err := auth.decodeMetadata(context.Background(), md) + after, err := auth.decodeMetadata(md) require.NoError(t, err) require.Equal(t, before.GetID(), after.GetID()) require.Equal(t, before.GetUID(), after.GetUID()) diff --git a/pkg/storage/unified/sql/service.go b/pkg/storage/unified/sql/service.go index 4397a48b6d4..6c05f884b27 100644 --- a/pkg/storage/unified/sql/service.go +++ b/pkg/storage/unified/sql/service.go @@ -80,7 +80,8 @@ func ProvideUnifiedStorageGrpcService( // FIXME: This is a temporary solution while we are migrating to the new authn interceptor // grpcutils.NewGrpcAuthenticator should be used instead. - authn, err := grpcutils.NewGrpcAuthenticatorWithFallback(cfg, reg, tracing, &grpc.Authenticator{}) + fallback := &grpc.Authenticator{Tracer: tracing} + authn, err := grpcutils.NewGrpcAuthenticatorWithFallback(cfg, reg, tracing, fallback) if err != nil { return nil, err }