diff --git a/pkg/apimachinery/identity/context.go b/pkg/apimachinery/identity/context.go index 046b743292f..ae71f06eaf1 100644 --- a/pkg/apimachinery/identity/context.go +++ b/pkg/apimachinery/identity/context.go @@ -5,14 +5,14 @@ import ( "fmt" "reflect" - claims "github.com/grafana/authlib/types" + "github.com/grafana/authlib/types" ) type ctxUserKey struct{} // WithRequester attaches the requester to the context. func WithRequester(ctx context.Context, usr Requester) context.Context { - ctx = claims.WithAuthInfo(ctx, usr) // also set the upstream auth info claims + ctx = types.WithAuthInfo(ctx, usr) // also set the upstream auth info claims return context.WithValue(ctx, ctxUserKey{}, usr) } @@ -29,3 +29,54 @@ func GetRequester(ctx context.Context) (Requester, error) { func checkNilRequester(r Requester) bool { return r == nil || (reflect.ValueOf(r).Kind() == reflect.Ptr && reflect.ValueOf(r).IsNil()) } + +const serviceName = "service" + +// WithServiceIdentitiy sets creates an identity representing the service itself in provided org and store it in context. +// This is useful for background tasks that has to communicate with unfied storage. It also returns a Requester with +// static permissions so it can be used in legacy code paths. +func WithServiceIdentitiy(ctx context.Context, orgID int64) (context.Context, Requester) { + r := &StaticRequester{ + Type: types.TypeAccessPolicy, + Name: serviceName, + UserUID: serviceName, + AuthID: serviceName, + Login: serviceName, + OrgRole: RoleAdmin, + IsGrafanaAdmin: true, + OrgID: orgID, + Permissions: map[int64]map[string][]string{ + orgID: serviceIdentityPermissions, + }, + } + + return WithRequester(ctx, r), r +} + +func getWildcardPermissions(actions ...string) map[string][]string { + permissions := make(map[string][]string, len(actions)) + for _, a := range actions { + permissions[a] = []string{"*"} + } + return permissions +} + +// serviceIdentityPermissions is a list of wildcard permissions for provided actions. +// We should add every action required "internally" here. +var serviceIdentityPermissions = getWildcardPermissions( + "folders:read", + "folders:write", + "folders:create", + "dashboards:read", + "dashboards:write", + "dashboards:create", + "datasources:read", +) + +func IsServiceIdentity(ctx context.Context) bool { + ident, err := GetRequester(ctx) + if err != nil { + return false + } + return ident.GetUID() == types.NewTypeID(types.TypeAccessPolicy, serviceName) +} diff --git a/pkg/apiserver/endpoints/filters/requester.go b/pkg/apiserver/endpoints/filters/requester.go index 12c19457435..ccdb2c5d2c2 100644 --- a/pkg/apiserver/endpoints/filters/requester.go +++ b/pkg/apiserver/endpoints/filters/requester.go @@ -16,7 +16,7 @@ import ( func WithRequester(handler http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { ctx := req.Context() - requester, err := identity.GetRequester(ctx) + _, err := identity.GetRequester(ctx) if err == nil { handler.ServeHTTP(w, req) return @@ -24,54 +24,27 @@ func WithRequester(handler http.Handler) http.Handler { // Find the kubernetes user info info, ok := request.UserFrom(ctx) - if ok { - if info.GetName() == user.Anonymous { - requester = &identity.StaticRequester{ - Type: claims.TypeAnonymous, - Name: info.GetName(), - Login: info.GetName(), - Permissions: map[int64]map[string][]string{}, - } - } - - if info.GetName() == user.APIServerUser || - slices.Contains(info.GetGroups(), user.SystemPrivilegedGroup) { - orgId := int64(1) - requester = &identity.StaticRequester{ - Type: claims.TypeServiceAccount, // system:apiserver - UserID: 1, - OrgID: orgId, - Name: info.GetName(), - Login: info.GetName(), - OrgRole: identity.RoleAdmin, - - IsGrafanaAdmin: true, - Namespace: "default", - - Permissions: map[int64]map[string][]string{ - orgId: { - "*": {"*"}, // all resources, all scopes - // FIXME(kalleep): We don't support wildcard actions so we need to list all possible actions - // for this user. This is not scalable and we should look into how to fix this. - "org.users:read": {"*"}, - // Dashboards do not support wildcard action - // dashboards.ActionDashboardsRead: {"*"}, - // dashboards.ActionDashboardsCreate: {"*"}, - // dashboards.ActionDashboardsWrite: {"*"}, - // dashboards.ActionDashboardsDelete: {"*"}, - // dashboards.ActionFoldersCreate: {"*"}, - // dashboards.ActionFoldersRead: {dashboards.ScopeFoldersAll}, // access to read all folders - }, - }, - } - } - - if requester != nil { - req = req.WithContext(identity.WithRequester(ctx, requester)) - } else { - klog.V(5).Info("unable to map the k8s user to grafana requester", "user", info) - } + if !ok { + handler.ServeHTTP(w, req) + return } + + if ok && info.GetName() == user.Anonymous { + req = req.WithContext(identity.WithRequester(ctx, &identity.StaticRequester{ + Type: claims.TypeAnonymous, + Name: info.GetName(), + Login: info.GetName(), + Permissions: map[int64]map[string][]string{}, + })) + } else if ok && info.GetName() == user.APIServerUser || + slices.Contains(info.GetGroups(), user.SystemPrivilegedGroup) { + // For system:apiserver we use the identity of the service itself + ctx, _ = identity.WithServiceIdentitiy(ctx, 1) + req = req.WithContext(ctx) + } else { + klog.V(5).Info("unable to map the k8s user to grafana requester", "user", info) + } + handler.ServeHTTP(w, req) }) } diff --git a/pkg/apiserver/rest/dualwriter_syncer.go b/pkg/apiserver/rest/dualwriter_syncer.go index 2b9aeb48d51..816de7ba50d 100644 --- a/pkg/apiserver/rest/dualwriter_syncer.go +++ b/pkg/apiserver/rest/dualwriter_syncer.go @@ -16,7 +16,6 @@ import ( "k8s.io/apiserver/pkg/registry/rest" "k8s.io/klog/v2" - claims "github.com/grafana/authlib/types" "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/apimachinery/utils" ) @@ -159,11 +158,8 @@ 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) - ctx = identity.WithRequester(ctx, getSyncRequester(orgId)) + ctx, _ = identity.WithServiceIdentitiy(ctx, 0) ctx = request.WithNamespace(ctx, cfg.RequestInfo.Namespace) ctx = request.WithRequestInfo(ctx, cfg.RequestInfo) @@ -298,23 +294,6 @@ func legacyToUnifiedStorageDataSyncer(ctx context.Context, cfg *SyncerConfig) (b return everythingSynced, err } -func getSyncRequester(orgId int64) *identity.StaticRequester { - return &identity.StaticRequester{ - Type: claims.TypeServiceAccount, // system:apiserver - UserID: 1, - OrgID: orgId, - Name: "admin", - Login: "admin", - OrgRole: identity.RoleAdmin, - IsGrafanaAdmin: true, - Permissions: map[int64]map[string][]string{ - orgId: { - "*": {"*"}, // all resources, all scopes - }, - }, - } -} - func getList(ctx context.Context, obj rest.Lister, listOptions *metainternalversion.ListOptions) ([]runtime.Object, error) { ll, err := obj.List(ctx, listOptions) if err != nil { diff --git a/pkg/services/accesscontrol/dualwrite/collectors.go b/pkg/services/accesscontrol/dualwrite/collectors.go index c5fee947a73..1e8f77f6875 100644 --- a/pkg/services/accesscontrol/dualwrite/collectors.go +++ b/pkg/services/accesscontrol/dualwrite/collectors.go @@ -5,12 +5,11 @@ import ( openfgav1 "github.com/openfga/api/proto/openfga/v1" + "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/infra/db" authzextv1 "github.com/grafana/grafana/pkg/services/authz/proto/v1" "github.com/grafana/grafana/pkg/services/authz/zanzana" - "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/folder" - "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" ) @@ -71,18 +70,11 @@ func folderTreeCollector(folderService folder.Service) legacyTupleCollector { ctx, span := tracer.Start(ctx, "accesscontrol.migrator.folderTreeCollector") defer span.End() - user := &user.SignedInUser{ - Login: "folder-tree-collector", - OrgRole: "Admin", - IsGrafanaAdmin: true, - IsServiceAccount: true, - Permissions: map[int64]map[string][]string{orgID: {dashboards.ActionFoldersRead: {dashboards.ScopeFoldersAll}}}, - OrgID: orgID, - } + ctx, ident := identity.WithServiceIdentitiy(ctx, orgID) q := folder.GetFoldersQuery{ OrgID: orgID, - SignedInUser: user, + SignedInUser: ident, } folders, err := folderService.GetFolders(ctx, q) diff --git a/pkg/services/authn/grpcutils/grpc_authenticator.go b/pkg/services/authn/grpcutils/grpc_authenticator.go index 421477ecb9d..500adda2b53 100644 --- a/pkg/services/authn/grpcutils/grpc_authenticator.go +++ b/pkg/services/authn/grpcutils/grpc_authenticator.go @@ -22,7 +22,6 @@ func NewInProcGrpcAuthenticator() *authnlib.GrpcAuthenticator { // In proc grpc ID token signature verification can be skipped return authnlib.NewUnsafeGrpcAuthenticator( &authnlib.GrpcAuthenticatorConfig{}, - authnlib.WithDisableAccessTokenAuthOption(), authnlib.WithIDTokenAuthOption(false), ) } diff --git a/pkg/services/authn/grpcutils/inproc_exchanger.go b/pkg/services/authn/grpcutils/inproc_exchanger.go new file mode 100644 index 00000000000..f7e24ffed7b --- /dev/null +++ b/pkg/services/authn/grpcutils/inproc_exchanger.go @@ -0,0 +1,61 @@ +package grpcutils + +import ( + "context" + "encoding/base64" + "encoding/json" + "fmt" + + "github.com/go-jose/go-jose/v3/jwt" + "github.com/grafana/authlib/authn" + "github.com/grafana/authlib/types" +) + +type inProcExchanger struct { + tokenResponse *authn.TokenExchangeResponse +} + +func ProvideInProcExchanger() *inProcExchanger { + tokenResponse, err := createInProcToken() + if err != nil { + panic(err) + } + + return &inProcExchanger{tokenResponse} +} + +func (e *inProcExchanger) Exchange(ctx context.Context, r authn.TokenExchangeRequest) (*authn.TokenExchangeResponse, error) { + return e.tokenResponse, nil +} + +func createInProcToken() (*authn.TokenExchangeResponse, error) { + claims := authn.Claims[authn.AccessTokenClaims]{ + Claims: jwt.Claims{ + Audience: []string{"resourceStore"}, + Issuer: "grafana", + Subject: types.NewTypeID(types.TypeAccessPolicy, "grafana"), + }, + Rest: authn.AccessTokenClaims{ + Namespace: "*", + Permissions: []string{"folder.grafana.app:*", "dashboard.grafana.app:*"}, + DelegatedPermissions: []string{"folder.grafana.app:*", "dashboard.grafana.app:*"}, + }, + } + + header, err := json.Marshal(map[string]string{ + "alg": "none", + "typ": authn.TokenTypeAccess, + }) + if err != nil { + return nil, err + } + + payload, err := json.Marshal(claims) + if err != nil { + return nil, err + } + + return &authn.TokenExchangeResponse{ + Token: fmt.Sprintf("%s.%s.", base64.RawURLEncoding.EncodeToString(header), base64.RawURLEncoding.EncodeToString(payload)), + }, nil +} diff --git a/pkg/services/dashboards/service/dashboard_service.go b/pkg/services/dashboards/service/dashboard_service.go index 3da1c24a2e3..e59070b8c24 100644 --- a/pkg/services/dashboards/service/dashboard_service.go +++ b/pkg/services/dashboards/service/dashboard_service.go @@ -37,7 +37,6 @@ import ( "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" dashboardsearch "github.com/grafana/grafana/pkg/services/dashboards/service/search" - "github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/services/guardian" @@ -54,14 +53,6 @@ import ( ) var ( - provisionerPermissions = []accesscontrol.Permission{ - {Action: dashboards.ActionFoldersCreate, Scope: dashboards.ScopeFoldersAll}, - {Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersAll}, - {Action: dashboards.ActionFoldersRead, Scope: dashboards.ScopeFoldersAll}, - {Action: dashboards.ActionDashboardsCreate, Scope: dashboards.ScopeFoldersAll}, - {Action: dashboards.ActionDashboardsWrite, Scope: dashboards.ScopeFoldersAll}, - {Action: datasources.ActionRead, Scope: datasources.ScopeAll}, - } // DashboardServiceImpl implements the DashboardService interface _ dashboards.DashboardService = (*DashboardServiceImpl)(nil) _ dashboards.DashboardProvisioningService = (*DashboardServiceImpl)(nil) @@ -164,7 +155,7 @@ func (dr *DashboardServiceImpl) Count(ctx context.Context, scopeParams *quota.Sc total := int64(0) for _, org := range orgs { - ctx = identity.WithRequester(ctx, getDashboardBackgroundRequester(org.ID)) + ctx, _ := identity.WithServiceIdentitiy(ctx, org.ID) orgDashboards, err := dr.CountDashboardsInOrg(ctx, org.ID) if err != nil { return nil, err @@ -228,21 +219,6 @@ func readQuotaConfig(cfg *setting.Cfg) (*quota.Map, error) { return limits, nil } -func getDashboardBackgroundRequester(orgId int64) *identity.StaticRequester { - return &identity.StaticRequester{ - Type: claims.TypeServiceAccount, - UserID: 1, - OrgID: orgId, - Name: "dashboard-background", - Login: "dashboard-background", - Permissions: map[int64]map[string][]string{ - orgId: { - "*": {"*"}, - }, - }, - } -} - func (dr *DashboardServiceImpl) GetProvisionedDashboardData(ctx context.Context, name string) ([]*dashboards.DashboardProvisioning, error) { if dr.features.IsEnabledGlobally(featuremgmt.FlagKubernetesCliDashboards) { orgs, err := dr.orgService.Search(ctx, &org.SearchOrgsQuery{}) @@ -581,6 +557,7 @@ func (dr *DashboardServiceImpl) DeleteOrphanedProvisionedDashboards(ctx context. } for _, org := range orgs { + ctx, _ := identity.WithServiceIdentitiy(ctx, org.ID) // find all dashboards in the org that have a file repo set that is not in the given readers list foundDashs, err := dr.searchProvisionedDashboardsThroughK8s(ctx, dashboards.FindPersistedDashboardsQuery{ ProvisionedReposNotIn: cmd.ReaderNames, @@ -592,7 +569,6 @@ func (dr *DashboardServiceImpl) DeleteOrphanedProvisionedDashboards(ctx context. // delete them for _, foundDash := range foundDashs { - ctx = identity.WithRequester(ctx, getDashboardBackgroundRequester(org.ID)) if err = dr.deleteDashboard(ctx, foundDash.DashboardID, foundDash.DashboardUID, org.ID, false); err != nil { return err } @@ -682,8 +658,8 @@ func (dr *DashboardServiceImpl) SaveProvisionedDashboard(ctx context.Context, dt dto.Dashboard.Data.Set("refresh", dr.cfg.MinRefreshInterval) } - dto.User = accesscontrol.BackgroundUser("dashboard_provisioning", dto.OrgID, org.RoleAdmin, provisionerPermissions) - ctx = identity.WithRequester(ctx, getDashboardBackgroundRequester(dto.OrgID)) + ctx, ident := identity.WithServiceIdentitiy(ctx, dto.OrgID) + dto.User = ident cmd, err := dr.BuildSaveDashboardCommand(ctx, dto, false) if err != nil { @@ -722,8 +698,8 @@ func (dr *DashboardServiceImpl) SaveFolderForProvisionedDashboards(ctx context.C ctx, span := tracer.Start(ctx, "dashboards.service.SaveFolderForProvisionedDashboards") defer span.End() - dto.SignedInUser = accesscontrol.BackgroundUser("dashboard_provisioning", dto.OrgID, org.RoleAdmin, provisionerPermissions) - ctx = identity.WithRequester(ctx, getDashboardBackgroundRequester(dto.OrgID)) + ctx, ident := identity.WithServiceIdentitiy(ctx, dto.OrgID) + dto.SignedInUser = ident f, err := dr.folderService.Create(ctx, dto) if err != nil { @@ -867,7 +843,7 @@ func (dr *DashboardServiceImpl) GetDashboardByPublicUid(ctx context.Context, das // DeleteProvisionedDashboard removes dashboard from the DB even if it is provisioned. func (dr *DashboardServiceImpl) DeleteProvisionedDashboard(ctx context.Context, dashboardId int64, orgId int64) error { - ctx = identity.WithRequester(ctx, getDashboardBackgroundRequester(orgId)) + ctx, _ = identity.WithServiceIdentitiy(ctx, orgId) return dr.deleteDashboard(ctx, dashboardId, "", orgId, false) } @@ -949,7 +925,7 @@ func (dr *DashboardServiceImpl) UnprovisionDashboard(ctx context.Context, dashbo } for _, org := range orgs { - ctx = identity.WithRequester(ctx, getDashboardBackgroundRequester(org.ID)) + ctx, _ = identity.WithServiceIdentitiy(ctx, org.ID) dash, err := dr.getDashboardThroughK8s(ctx, &dashboards.GetDashboardQuery{OrgID: org.ID, ID: dashboardId}) if err != nil { // if we can't find it in this org, try the next one @@ -1720,7 +1696,7 @@ type dashboardProvisioningWithUID struct { } func (dr *DashboardServiceImpl) searchProvisionedDashboardsThroughK8s(ctx context.Context, query dashboards.FindPersistedDashboardsQuery) ([]*dashboardProvisioningWithUID, error) { - ctx = identity.WithRequester(ctx, getDashboardBackgroundRequester(query.OrgId)) + ctx, _ = identity.WithServiceIdentitiy(ctx, query.OrgId) if query.ProvisionedRepo != "" { query.ProvisionedRepo = provisionedFileNameWithPrefix(query.ProvisionedRepo) diff --git a/pkg/services/stats/statsimpl/stats.go b/pkg/services/stats/statsimpl/stats.go index cd379f23242..6cebff6ee19 100644 --- a/pkg/services/stats/statsimpl/stats.go +++ b/pkg/services/stats/statsimpl/stats.go @@ -6,7 +6,6 @@ import ( "strconv" "time" - claims "github.com/grafana/authlib/types" "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/services/dashboards" @@ -45,7 +44,7 @@ type sqlStatsService struct { func (ss *sqlStatsService) getDashboardCount(ctx context.Context, orgs []*org.OrgDTO) (int64, error) { count := int64(0) for _, org := range orgs { - ctx = identity.WithRequester(ctx, getStatsRequester(org.ID)) + ctx, _ = identity.WithServiceIdentitiy(ctx, org.ID) dashsCount, err := ss.dashSvc.CountDashboardsInOrg(ctx, org.ID) if err != nil { return 0, err @@ -59,7 +58,7 @@ func (ss *sqlStatsService) getDashboardCount(ctx context.Context, orgs []*org.Or func (ss *sqlStatsService) getTagCount(ctx context.Context, orgs []*org.OrgDTO) (int64, error) { total := 0 for _, org := range orgs { - ctx = identity.WithRequester(ctx, getStatsRequester(org.ID)) + ctx, _ = identity.WithServiceIdentitiy(ctx, org.ID) tags, err := ss.dashSvc.GetDashboardTags(ctx, &dashboards.GetDashboardTagsQuery{ OrgID: org.ID, }) @@ -75,11 +74,10 @@ func (ss *sqlStatsService) getTagCount(ctx context.Context, orgs []*org.OrgDTO) func (ss *sqlStatsService) getFolderCount(ctx context.Context, orgs []*org.OrgDTO) (int64, error) { total := 0 for _, org := range orgs { - backgroundUser := getStatsRequester(org.ID) - ctx = identity.WithRequester(ctx, backgroundUser) + ctx, ident := identity.WithServiceIdentitiy(ctx, org.ID) folders, err := ss.folderSvc.GetFolders(ctx, folder.GetFoldersQuery{ OrgID: org.ID, - SignedInUser: backgroundUser, + SignedInUser: ident, }) if err != nil { return 0, err @@ -438,18 +436,3 @@ func addToStats(base stats.UserStats, role org.RoleType, count int64) stats.User return base } - -func getStatsRequester(orgId int64) *identity.StaticRequester { - return &identity.StaticRequester{ - Type: claims.TypeServiceAccount, - UserID: 1, - OrgID: orgId, - Name: "stats-requester", - Login: "stats-requester", - Permissions: map[int64]map[string][]string{ - orgId: { - "*": {"*"}, - }, - }, - } -} diff --git a/pkg/storage/unified/resource/client.go b/pkg/storage/unified/resource/client.go index 068fee8f92d..bd67e68d428 100644 --- a/pkg/storage/unified/resource/client.go +++ b/pkg/storage/unified/resource/client.go @@ -4,6 +4,7 @@ import ( "context" "crypto/tls" "fmt" + "log/slog" "net/http" "github.com/fullstorydev/grpchan" @@ -12,7 +13,8 @@ import ( "google.golang.org/grpc" authnlib "github.com/grafana/authlib/authn" - claims "github.com/grafana/authlib/types" + "github.com/grafana/authlib/types" + "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/services/authn/grpcutils" @@ -70,8 +72,8 @@ func NewLocalResourceClient(server ResourceServer) ResourceClient { } clientInt, _ := authnlib.NewGrpcClientInterceptor( - &authnlib.GrpcClientConfig{}, - authnlib.WithDisableAccessTokenOption(), + &authnlib.GrpcClientConfig{TokenRequest: &authnlib.TokenExchangeRequest{}}, + authnlib.WithTokenClientOption(grpcutils.ProvideInProcExchanger()), authnlib.WithIDTokenExtractorOption(idTokenExtractor), ) @@ -131,15 +133,28 @@ func NewCloudResourceClient(tracer tracing.Tracer, conn *grpc.ClientConn, cfg au }, nil } +var authLogger = slog.Default().With("logger", "resource-client-auth-interceptor") + func idTokenExtractor(ctx context.Context) (string, error) { - authInfo, ok := claims.AuthInfoFrom(ctx) + if identity.IsServiceIdentity(ctx) { + return "", nil + } + + info, ok := types.AuthInfoFrom(ctx) if !ok { return "", fmt.Errorf("no claims found") } - extra := authInfo.GetExtra() - if token, exists := extra["id-token"]; exists && len(token) != 0 && token[0] != "" { - return token[0], nil + if token := info.GetIDToken(); len(token) != 0 { + return token, nil + } + + if !types.IsIdentityType(info.GetIdentityType(), types.TypeAccessPolicy) { + authLogger.Warn( + "calling resource store as the service without id token or marking it as the service identity", + "subject", info.GetSubject(), + "uid", info.GetUID(), + ) } return "", nil diff --git a/pkg/storage/unified/resource/client_test.go b/pkg/storage/unified/resource/client_test.go index 4c252c08f42..e8c0981b57d 100644 --- a/pkg/storage/unified/resource/client_test.go +++ b/pkg/storage/unified/resource/client_test.go @@ -6,7 +6,6 @@ import ( "github.com/stretchr/testify/assert" - claims "github.com/grafana/authlib/types" "github.com/grafana/grafana/pkg/apimachinery/identity" ) @@ -16,11 +15,8 @@ func TestIDTokenExtractor(t *testing.T) { 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, - }) + t.Run("should return an empty token when grafana identity is set", func(t *testing.T) { + ctx, _ := identity.WithServiceIdentitiy(context.Background(), 0) token, err := idTokenExtractor(ctx) assert.NoError(t, err) assert.Empty(t, token) diff --git a/pkg/storage/unified/resource/server.go b/pkg/storage/unified/resource/server.go index 318d8cabfbf..fab1e585486 100644 --- a/pkg/storage/unified/resource/server.go +++ b/pkg/storage/unified/resource/server.go @@ -20,7 +20,6 @@ import ( "k8s.io/apimachinery/pkg/types" claims "github.com/grafana/authlib/types" - "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/apimachinery/utils" ) @@ -233,13 +232,7 @@ func NewResourceServer(opts ResourceServerOptions) (ResourceServer, error) { } // Make this cancelable - ctx, cancel := context.WithCancel(claims.WithAuthInfo(context.Background(), - &identity.StaticRequester{ - Type: claims.TypeServiceAccount, - Login: "watcher", // admin user for watch - UserID: 1, - IsGrafanaAdmin: true, - })) + ctx, cancel := context.WithCancel(context.Background()) s := &server{ tracer: opts.Tracer, log: logger, diff --git a/pkg/storage/unified/sql/test/integration_test.go b/pkg/storage/unified/sql/test/integration_test.go index c977784714f..5883610bd54 100644 --- a/pkg/storage/unified/sql/test/integration_test.go +++ b/pkg/storage/unified/sql/test/integration_test.go @@ -5,15 +5,16 @@ import ( "testing" "time" + "github.com/go-jose/go-jose/v3/jwt" "github.com/prometheus/client_golang/prometheus" "github.com/stretchr/testify/require" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - claims "github.com/grafana/authlib/types" + "github.com/grafana/authlib/authn" + "github.com/grafana/authlib/types" "github.com/grafana/dskit/services" - "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/apimachinery/utils" infraDB "github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/infra/tracing" @@ -70,15 +71,13 @@ func TestIntegrationBackendHappyPath(t *testing.T) { t.Skip("skipping integration test") } - testUserA := &identity.StaticRequester{ - Type: claims.TypeUser, - Login: "testuser", - UserID: 123, - UserUID: "u123", - OrgRole: identity.RoleAdmin, - IsGrafanaAdmin: true, // can do anything - } - ctx := identity.WithRequester(context.Background(), testUserA) + ctx := types.WithAuthInfo(context.Background(), authn.NewAccessTokenAuthInfo(authn.Claims[authn.AccessTokenClaims]{ + Claims: jwt.Claims{ + Subject: "testuser", + }, + Rest: authn.AccessTokenClaims{}, + })) + backend, server := newServer(t, nil) stream, err := backend.WatchWriteEvents(context.Background()) // Using a different context to avoid canceling the stream after the DefaultContextTimeout @@ -420,15 +419,12 @@ func TestClientServer(t *testing.T) { require.NoError(t, err) var client resource.ResourceStoreClient - // Test with an admin identity - clientCtx := identity.WithRequester(ctx, &identity.StaticRequester{ - Type: claims.TypeUser, - Login: "testuser", - UserID: 123, - UserUID: "u123", - OrgRole: identity.RoleAdmin, - IsGrafanaAdmin: true, // can do anything - }) + clientCtx := types.WithAuthInfo(context.Background(), authn.NewAccessTokenAuthInfo(authn.Claims[authn.AccessTokenClaims]{ + Claims: jwt.Claims{ + Subject: "testuser", + }, + Rest: authn.AccessTokenClaims{}, + })) t.Run("Start and stop service", func(t *testing.T) { err = services.StartAndAwaitRunning(ctx, svc)