fix: Add panic for nil authorizer in installer (#115186)
This commit is contained in:
@@ -38,6 +38,7 @@ func RegisterAPIService(features featuremgmt.FeatureToggles, apiregistration bui
|
||||
}
|
||||
|
||||
func (b *ServiceAPIBuilder) GetAuthorizer() authorizer.Authorizer {
|
||||
//nolint:staticcheck // not yet migrated to Resource Authorizer
|
||||
return roleauthorizer.NewRoleAuthorizer()
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/app"
|
||||
@@ -16,6 +17,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
"github.com/grafana/grafana/pkg/apiserver/rest"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/appinstaller"
|
||||
roleauthorizer "github.com/grafana/grafana/pkg/services/apiserver/auth/authorizer"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
|
||||
"github.com/grafana/grafana/pkg/services/correlations"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
@@ -60,6 +62,11 @@ func RegisterAppInstaller(
|
||||
return installer, nil
|
||||
}
|
||||
|
||||
func (a *AppInstaller) GetAuthorizer() authorizer.Authorizer {
|
||||
//nolint:staticcheck // not yet migrated to Resource Authorizer
|
||||
return roleauthorizer.NewRoleAuthorizer()
|
||||
}
|
||||
|
||||
func (a *AppInstaller) GetLegacyStorage(requested schema.GroupVersionResource) rest.Storage {
|
||||
kind := correlationsV0.CorrelationKind()
|
||||
gvr := schema.GroupVersionResource{
|
||||
|
||||
@@ -6,17 +6,20 @@ import (
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/app"
|
||||
appsdkapiserver "github.com/grafana/grafana-app-sdk/k8s/apiserver"
|
||||
"github.com/grafana/grafana-app-sdk/simple"
|
||||
|
||||
"github.com/grafana/grafana/apps/playlist/pkg/apis"
|
||||
playlistv0alpha1 "github.com/grafana/grafana/apps/playlist/pkg/apis/playlist/v0alpha1"
|
||||
playlistapp "github.com/grafana/grafana/apps/playlist/pkg/app"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/appinstaller"
|
||||
roleauthorizer "github.com/grafana/grafana/pkg/services/apiserver/auth/authorizer"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
playlistsvc "github.com/grafana/grafana/pkg/services/playlist"
|
||||
@@ -63,6 +66,11 @@ func RegisterAppInstaller(
|
||||
return installer, nil
|
||||
}
|
||||
|
||||
func (p *PlaylistAppInstaller) GetAuthorizer() authorizer.Authorizer {
|
||||
//nolint:staticcheck // not yet migrated to Resource Authorizer
|
||||
return roleauthorizer.NewRoleAuthorizer()
|
||||
}
|
||||
|
||||
// GetLegacyStorage returns the legacy storage for the playlist app.
|
||||
func (p *PlaylistAppInstaller) GetLegacyStorage(requested schema.GroupVersionResource) grafanarest.Storage {
|
||||
gvr := playlistv0alpha1.PlaylistKind().GroupVersionResource()
|
||||
|
||||
@@ -3,12 +3,14 @@ package quotas
|
||||
import (
|
||||
"github.com/grafana/grafana/apps/quotas/pkg/apis"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/resource"
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/app"
|
||||
appsdkapiserver "github.com/grafana/grafana-app-sdk/k8s/apiserver"
|
||||
"github.com/grafana/grafana-app-sdk/simple"
|
||||
quotasapp "github.com/grafana/grafana/apps/quotas/pkg/app"
|
||||
roleauthorizer "github.com/grafana/grafana/pkg/services/apiserver/auth/authorizer"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
@@ -22,6 +24,11 @@ type QuotasAppInstaller struct {
|
||||
cfg *setting.Cfg
|
||||
}
|
||||
|
||||
func (a *QuotasAppInstaller) GetAuthorizer() authorizer.Authorizer {
|
||||
//nolint:staticcheck // not yet migrated to Resource Authorizer
|
||||
return roleauthorizer.NewRoleAuthorizer()
|
||||
}
|
||||
|
||||
func RegisterAppInstaller(
|
||||
cfg *setting.Cfg,
|
||||
features featuremgmt.FeatureToggles,
|
||||
|
||||
@@ -114,6 +114,8 @@ func RegisterAuthorizers(
|
||||
registrar.Register(gv, authorizer)
|
||||
logger.Debug("Registered authorizer", "group", gv.Group, "version", gv.Version, "app")
|
||||
}
|
||||
} else {
|
||||
panic("authorizer cannot be nil for api group: " + installer.GroupVersions()[0].Group)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ func TestRegisterAuthorizers(t *testing.T) {
|
||||
name string
|
||||
appInstallers []appsdkapiserver.AppInstaller
|
||||
expectedRegisters int
|
||||
expectedPanic bool
|
||||
}{
|
||||
{
|
||||
name: "empty installers list",
|
||||
@@ -30,7 +31,7 @@ func TestRegisterAuthorizers(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedRegisters: 0,
|
||||
expectedPanic: true,
|
||||
},
|
||||
{
|
||||
name: "single installer with authorizer provider",
|
||||
@@ -46,6 +47,20 @@ func TestRegisterAuthorizers(t *testing.T) {
|
||||
},
|
||||
expectedRegisters: 1,
|
||||
},
|
||||
{
|
||||
name: "single installer with invalid authorizer provider",
|
||||
appInstallers: []appsdkapiserver.AppInstaller{
|
||||
&mockAppInstallerWithAuth{
|
||||
mockAppInstaller: &mockAppInstaller{
|
||||
groupVersions: []schema.GroupVersion{
|
||||
{Group: "test.example.com", Version: "v1"},
|
||||
},
|
||||
},
|
||||
mockAuthorizer: nil,
|
||||
},
|
||||
},
|
||||
expectedPanic: true,
|
||||
},
|
||||
{
|
||||
name: "installer with multiple group versions",
|
||||
appInstallers: []appsdkapiserver.AppInstaller{
|
||||
@@ -63,7 +78,7 @@ func TestRegisterAuthorizers(t *testing.T) {
|
||||
expectedRegisters: 3,
|
||||
},
|
||||
{
|
||||
name: "multiple installers with mixed authorizer support",
|
||||
name: "multiple installers with authorizer support",
|
||||
appInstallers: []appsdkapiserver.AppInstaller{
|
||||
&mockAppInstallerWithAuth{
|
||||
mockAppInstaller: &mockAppInstaller{
|
||||
@@ -73,11 +88,6 @@ func TestRegisterAuthorizers(t *testing.T) {
|
||||
},
|
||||
mockAuthorizer: &mockAuthorizer{},
|
||||
},
|
||||
&mockAppInstaller{
|
||||
groupVersions: []schema.GroupVersion{
|
||||
{Group: "other.example.com", Version: "v1"},
|
||||
},
|
||||
},
|
||||
&mockAppInstallerWithAuth{
|
||||
mockAppInstaller: &mockAppInstaller{
|
||||
groupVersions: []schema.GroupVersion{
|
||||
@@ -88,7 +98,7 @@ func TestRegisterAuthorizers(t *testing.T) {
|
||||
mockAuthorizer: &mockAuthorizer{},
|
||||
},
|
||||
},
|
||||
expectedRegisters: 3, // 1 from first installer + 2 from third installer
|
||||
expectedRegisters: 3, // 1 from first installer + 2 from second installer
|
||||
},
|
||||
}
|
||||
|
||||
@@ -96,6 +106,13 @@ func TestRegisterAuthorizers(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
registrar := &mockAuthorizerRegistrar{}
|
||||
if tt.expectedPanic {
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
t.Errorf("%s case did not panic as expected", t.Name())
|
||||
}
|
||||
}()
|
||||
}
|
||||
RegisterAuthorizers(ctx, tt.appInstallers, registrar)
|
||||
require.Equal(t, tt.expectedRegisters, len(registrar.registrations))
|
||||
})
|
||||
|
||||
@@ -38,12 +38,12 @@ func NewGrafanaBuiltInSTAuthorizer(cfg *setting.Cfg) *GrafanaAuthorizer {
|
||||
|
||||
// Individual services may have explicit implementations
|
||||
apis := make(map[string]authorizer.Authorizer)
|
||||
// The apiVersion flavors will run first and can return early when FGAC has appropriate rules
|
||||
authorizers = append(authorizers, &authorizerForAPI{apis})
|
||||
|
||||
// org role is last -- and will return allow for verbs that match expectations
|
||||
// The apiVersion flavors will run first and can return early when FGAC has appropriate rules
|
||||
// NOTE: role authorizer is now used by some api groups as their specific authorizer
|
||||
// but there are still some apis not directly registered in the embedded delegate that benefit from including it here
|
||||
// org role authorizer is last -- and will return allow for verbs that match expectations
|
||||
// it is only helpful here for remote APIs in some cloud use-cases.
|
||||
//nolint:staticcheck // remove once build handler chains are untangled between local and remote APIs handling
|
||||
authorizers = append(authorizers, NewRoleAuthorizer())
|
||||
return &GrafanaAuthorizer{
|
||||
apis: apis,
|
||||
|
||||
@@ -19,6 +19,7 @@ var orgRoleNoneAsViewerAPIGroups = []string{
|
||||
|
||||
type roleAuthorizer struct{}
|
||||
|
||||
// Deprecated: NewRoleAuthorizer exists for apps that were launched with simplistic authorization requirements. Consider using NewResourceAuthorizer instead.
|
||||
func NewRoleAuthorizer() *roleAuthorizer {
|
||||
return &roleAuthorizer{}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user