mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Authenticator: Return gRPC errors (#99000)
This commit is contained in:
parent
98e9f3a534
commit
70ddf9cb76
@ -2,16 +2,17 @@ package grpc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/metadata"
|
"google.golang.org/grpc/metadata"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
|
|
||||||
"github.com/grafana/authlib/authn"
|
|
||||||
authClaims "github.com/grafana/authlib/claims"
|
authClaims "github.com/grafana/authlib/claims"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -27,10 +28,13 @@ const (
|
|||||||
// var _ interceptors.Authenticator = (*Authenticator)(nil)
|
// var _ interceptors.Authenticator = (*Authenticator)(nil)
|
||||||
|
|
||||||
type Authenticator struct {
|
type Authenticator struct {
|
||||||
IDTokenVerifier authn.Verifier[authn.IDTokenClaims]
|
Tracer tracing.Tracer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Authenticator) Authenticate(ctx context.Context) (context.Context, error) {
|
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)
|
r, err := identity.GetRequester(ctx)
|
||||||
if err == nil && r != nil {
|
if err == nil && r != nil {
|
||||||
return ctx, nil // noop, requester exists
|
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)
|
md, ok := metadata.FromIncomingContext(ctx)
|
||||||
if !ok {
|
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 {
|
if err != nil {
|
||||||
|
span.RecordError(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return identity.WithRequester(ctx, user), nil
|
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
|
// Avoid NPE/panic with getting keys
|
||||||
getter := func(key string) string {
|
getter := func(key string) string {
|
||||||
v := meta.Get(key)
|
v := meta.Get(key)
|
||||||
@ -57,20 +64,10 @@ func (f *Authenticator) decodeMetadata(ctx context.Context, meta metadata.MD) (i
|
|||||||
return ""
|
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 := &identity.StaticRequester{}
|
||||||
user.Login = getter(mdLogin)
|
user.Login = getter(mdLogin)
|
||||||
if user.Login == "" {
|
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
|
// 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.Type = authClaims.TypeUser
|
||||||
user.UserID, err = strconv.ParseInt(getter("grafana-userid"), 10, 64)
|
user.UserID, err = strconv.ParseInt(getter("grafana-userid"), 10, 64)
|
||||||
if err != nil {
|
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)
|
user.OrgID, err = strconv.ParseInt(getter("grafana-orgid"), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("invalid org id: %w", err)
|
return nil, status.Error(codes.Unauthenticated, "invalid org id")
|
||||||
}
|
}
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
typ, id, err := authClaims.ParseTypeID(getter(mdUserID))
|
typ, id, err := authClaims.ParseTypeID(getter(mdUserID))
|
||||||
if err != nil {
|
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.Type = typ
|
||||||
user.UserID, err = strconv.ParseInt(id, 10, 64)
|
user.UserID, err = strconv.ParseInt(id, 10, 64)
|
||||||
if err != nil {
|
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 {
|
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)
|
user.OrgID, err = strconv.ParseInt(getter(mdOrgID), 10, 64)
|
||||||
if err != nil {
|
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))
|
user.OrgRole = identity.RoleType(getter(mdOrgRole))
|
||||||
return user, nil
|
return user, nil
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
package grpc
|
package grpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/grafana/authlib/claims"
|
"github.com/grafana/authlib/claims"
|
||||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBasicEncodeDecode(t *testing.T) {
|
func TestBasicEncodeDecode(t *testing.T) {
|
||||||
@ -20,10 +20,10 @@ func TestBasicEncodeDecode(t *testing.T) {
|
|||||||
OrgRole: identity.RoleAdmin,
|
OrgRole: identity.RoleAdmin,
|
||||||
}
|
}
|
||||||
|
|
||||||
auth := &Authenticator{}
|
auth := &Authenticator{Tracer: tracing.NewNoopTracerService()}
|
||||||
|
|
||||||
md := encodeIdentityInMetadata(before)
|
md := encodeIdentityInMetadata(before)
|
||||||
after, err := auth.decodeMetadata(context.Background(), md)
|
after, err := auth.decodeMetadata(md)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, before.GetID(), after.GetID())
|
require.Equal(t, before.GetID(), after.GetID())
|
||||||
require.Equal(t, before.GetUID(), after.GetUID())
|
require.Equal(t, before.GetUID(), after.GetUID())
|
||||||
|
@ -80,7 +80,8 @@ func ProvideUnifiedStorageGrpcService(
|
|||||||
|
|
||||||
// FIXME: This is a temporary solution while we are migrating to the new authn interceptor
|
// FIXME: This is a temporary solution while we are migrating to the new authn interceptor
|
||||||
// grpcutils.NewGrpcAuthenticator should be used instead.
|
// 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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user