mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
[auth] make id-token optional (#97831)
make idtoken optional enure there is always an identity in the context fix: update token fix: now it should work fix: now it should work
This commit is contained in:
parent
02fec7c4ad
commit
3fe2227c82
@ -17,7 +17,6 @@ import (
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
"github.com/grafana/authlib/claims"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
)
|
||||
@ -160,6 +159,7 @@ func legacyToUnifiedStorageDataSyncer(ctx context.Context, cfg *SyncerConfig) (b
|
||||
log.Info("starting legacyToUnifiedStorageDataSyncer")
|
||||
startSync := time.Now()
|
||||
|
||||
// Add a claim to the context to allow the background job to use the underlying access_token permissions.
|
||||
orgId := int64(1)
|
||||
|
||||
ctx = klog.NewContext(ctx, log)
|
||||
|
@ -23,7 +23,7 @@ func NewInProcGrpcAuthenticator() *authnlib.GrpcAuthenticator {
|
||||
return authnlib.NewUnsafeGrpcAuthenticator(
|
||||
&authnlib.GrpcAuthenticatorConfig{},
|
||||
authnlib.WithDisableAccessTokenAuthOption(),
|
||||
authnlib.WithIDTokenAuthOption(true),
|
||||
authnlib.WithIDTokenAuthOption(false),
|
||||
)
|
||||
}
|
||||
|
||||
@ -47,21 +47,14 @@ func NewGrpcAuthenticator(authCfg *GrpcServerConfig, tracer tracing.Tracer) (*au
|
||||
grpcOpts := []authnlib.GrpcAuthenticatorOption{
|
||||
authnlib.WithKeyRetrieverOption(keyRetriever),
|
||||
authnlib.WithTracerAuthOption(tracer),
|
||||
authnlib.WithIDTokenAuthOption(false),
|
||||
}
|
||||
switch authCfg.Mode {
|
||||
case ModeOnPrem:
|
||||
if authCfg.Mode == ModeOnPrem {
|
||||
grpcOpts = append(grpcOpts,
|
||||
// Access token are not yet available on-prem
|
||||
authnlib.WithDisableAccessTokenAuthOption(),
|
||||
authnlib.WithIDTokenAuthOption(true),
|
||||
)
|
||||
case ModeCloud:
|
||||
grpcOpts = append(grpcOpts,
|
||||
// ID tokens are enabled but not required in cloud
|
||||
authnlib.WithIDTokenAuthOption(false),
|
||||
)
|
||||
}
|
||||
|
||||
return authnlib.NewGrpcAuthenticator(
|
||||
&grpcAuthCfg,
|
||||
grpcOpts...,
|
||||
|
@ -5,20 +5,15 @@ import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/fullstorydev/grpchan"
|
||||
"github.com/fullstorydev/grpchan/inprocgrpc"
|
||||
"github.com/go-jose/go-jose/v3"
|
||||
"github.com/go-jose/go-jose/v3/jwt"
|
||||
authnlib "github.com/grafana/authlib/authn"
|
||||
"github.com/grafana/authlib/claims"
|
||||
grpcAuth "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/auth"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/services/auth"
|
||||
"github.com/grafana/grafana/pkg/services/authn/grpcutils"
|
||||
grpcUtils "github.com/grafana/grafana/pkg/storage/unified/resource/grpc"
|
||||
)
|
||||
@ -139,19 +134,7 @@ func idTokenExtractor(ctx context.Context) (string, error) {
|
||||
return token[0], nil
|
||||
}
|
||||
|
||||
// If no token is found, create an internal token.
|
||||
// This is a workaround for StaticRequester not having a signed ID token.
|
||||
if staticRequester, ok := authInfo.(*identity.StaticRequester); ok {
|
||||
token, _, err := createInternalToken(staticRequester)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create internal token: %w", err)
|
||||
}
|
||||
|
||||
staticRequester.IDToken = token
|
||||
return token, nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("id-token not found")
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func allowInsecureTransportOpt(grpcClientConfig *authnlib.GrpcClientConfig, opts []authnlib.GrpcClientInterceptorOption) []authnlib.GrpcClientInterceptorOption {
|
||||
@ -159,45 +142,3 @@ func allowInsecureTransportOpt(grpcClientConfig *authnlib.GrpcClientConfig, opts
|
||||
tokenClient, _ := authnlib.NewTokenExchangeClient(*grpcClientConfig.TokenClientConfig, authnlib.WithHTTPClient(client))
|
||||
return append(opts, authnlib.WithTokenClientOption(tokenClient))
|
||||
}
|
||||
|
||||
// createInternalToken creates a symmetrically signed token for using in in-proc mode only.
|
||||
func createInternalToken(authInfo claims.AuthInfo) (string, *authnlib.Claims[authnlib.IDTokenClaims], error) {
|
||||
signerOpts := jose.SignerOptions{}
|
||||
signerOpts.WithType("jwt") // Should be uppercase, but this is what authlib expects
|
||||
signer, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.HS256, Key: []byte("internal key")}, &signerOpts)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
tokenTTL := 10 * time.Minute
|
||||
idClaims := &auth.IDClaims{
|
||||
Claims: jwt.Claims{
|
||||
Audience: authInfo.GetAudience(),
|
||||
Subject: authInfo.GetSubject(),
|
||||
Expiry: jwt.NewNumericDate(now.Add(tokenTTL)),
|
||||
IssuedAt: jwt.NewNumericDate(now),
|
||||
},
|
||||
Rest: authnlib.IDTokenClaims{
|
||||
Namespace: authInfo.GetNamespace(),
|
||||
Identifier: authInfo.GetIdentifier(),
|
||||
Type: authInfo.GetIdentityType(),
|
||||
},
|
||||
}
|
||||
|
||||
if claims.IsIdentityType(authInfo.GetIdentityType(), claims.TypeUser) {
|
||||
idClaims.Rest.Email = authInfo.GetEmail()
|
||||
idClaims.Rest.EmailVerified = authInfo.GetEmailVerified()
|
||||
idClaims.Rest.AuthenticatedBy = authInfo.GetAuthenticatedBy()
|
||||
idClaims.Rest.Username = authInfo.GetUsername()
|
||||
idClaims.Rest.DisplayName = authInfo.GetName()
|
||||
}
|
||||
|
||||
builder := jwt.Signed(signer).Claims(&idClaims.Rest).Claims(idClaims.Claims)
|
||||
token, err := builder.CompactSerialize()
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
return token, idClaims, nil
|
||||
}
|
||||
|
27
pkg/storage/unified/resource/client_test.go
Normal file
27
pkg/storage/unified/resource/client_test.go
Normal file
@ -0,0 +1,27 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/authlib/claims"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestIDTokenExtractor(t *testing.T) {
|
||||
t.Run("should return an error when no claims found", func(t *testing.T) {
|
||||
token, err := idTokenExtractor(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Empty(t, token)
|
||||
})
|
||||
t.Run("should return an empty token for static requester of type service account as grafana admin ", func(t *testing.T) {
|
||||
ctx := identity.WithRequester(context.Background(), &identity.StaticRequester{
|
||||
Type: claims.TypeServiceAccount,
|
||||
IsGrafanaAdmin: true,
|
||||
})
|
||||
token, err := idTokenExtractor(ctx)
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, token)
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue
Block a user