mirror of
https://github.com/grafana/grafana.git
synced 2025-07-29 19:52:35 +08:00
SaveExternalService (OAuth) on plugin load (#69764)
This commit is contained in:

committed by
GitHub

parent
f436364f9b
commit
4ff0abd0d1
@ -72,7 +72,7 @@ func TestCallResource(t *testing.T) {
|
|||||||
l := loader.ProvideService(pCfg, fakes.NewFakeLicensingService(), signature.NewUnsignedAuthorizer(pCfg),
|
l := loader.ProvideService(pCfg, fakes.NewFakeLicensingService(), signature.NewUnsignedAuthorizer(pCfg),
|
||||||
reg, provider.ProvideService(coreRegistry), finder.NewLocalFinder(pCfg), fakes.NewFakeRoleRegistry(),
|
reg, provider.ProvideService(coreRegistry), finder.NewLocalFinder(pCfg), fakes.NewFakeRoleRegistry(),
|
||||||
assetpath.ProvideService(pluginscdn.ProvideService(pCfg)), signature.ProvideService(pCfg, statickey.New()),
|
assetpath.ProvideService(pluginscdn.ProvideService(pCfg)), signature.ProvideService(pCfg, statickey.New()),
|
||||||
angularInspector)
|
angularInspector, &fakes.FakeOauthService{})
|
||||||
srcs := sources.ProvideService(cfg, pCfg)
|
srcs := sources.ProvideService(cfg, pCfg)
|
||||||
ps, err := store.ProvideService(reg, srcs, l)
|
ps, err := store.ProvideService(reg, srcs, l)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -38,6 +38,8 @@ type Cfg struct {
|
|||||||
|
|
||||||
GrafanaComURL string
|
GrafanaComURL string
|
||||||
|
|
||||||
|
GrafanaAppURL string
|
||||||
|
|
||||||
Features plugins.FeatureToggles
|
Features plugins.FeatureToggles
|
||||||
|
|
||||||
AngularSupportEnabled bool
|
AngularSupportEnabled bool
|
||||||
@ -45,7 +47,7 @@ type Cfg struct {
|
|||||||
|
|
||||||
func NewCfg(devMode bool, pluginsPath string, pluginSettings setting.PluginSettings, pluginsAllowUnsigned []string,
|
func NewCfg(devMode bool, pluginsPath string, pluginSettings setting.PluginSettings, pluginsAllowUnsigned []string,
|
||||||
awsAllowedAuthProviders []string, awsAssumeRoleEnabled bool, azure *azsettings.AzureSettings, secureSocksDSProxy setting.SecureSocksDSProxySettings,
|
awsAllowedAuthProviders []string, awsAssumeRoleEnabled bool, azure *azsettings.AzureSettings, secureSocksDSProxy setting.SecureSocksDSProxySettings,
|
||||||
grafanaVersion string, logDatasourceRequests bool, pluginsCDNURLTemplate string, tracing Tracing, features plugins.FeatureToggles, angularSupportEnabled bool,
|
grafanaVersion string, logDatasourceRequests bool, pluginsCDNURLTemplate string, appURL string, tracing Tracing, features plugins.FeatureToggles, angularSupportEnabled bool,
|
||||||
grafanaComURL string) *Cfg {
|
grafanaComURL string) *Cfg {
|
||||||
return &Cfg{
|
return &Cfg{
|
||||||
log: log.New("plugin.cfg"),
|
log: log.New("plugin.cfg"),
|
||||||
@ -62,6 +64,7 @@ func NewCfg(devMode bool, pluginsPath string, pluginSettings setting.PluginSetti
|
|||||||
PluginsCDNURLTemplate: pluginsCDNURLTemplate,
|
PluginsCDNURLTemplate: pluginsCDNURLTemplate,
|
||||||
Tracing: tracing,
|
Tracing: tracing,
|
||||||
GrafanaComURL: grafanaComURL,
|
GrafanaComURL: grafanaComURL,
|
||||||
|
GrafanaAppURL: appURL,
|
||||||
Features: features,
|
Features: features,
|
||||||
AngularSupportEnabled: angularSupportEnabled,
|
AngularSupportEnabled: angularSupportEnabled,
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Provider interface {
|
type Provider interface {
|
||||||
Get(ctx context.Context, p *plugins.Plugin) []string
|
Get(ctx context.Context, p *plugins.Plugin) ([]string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Service struct {
|
type Service struct {
|
||||||
@ -31,7 +31,7 @@ func NewProvider(cfg *config.Cfg, license plugins.Licensing) *Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) Get(_ context.Context, p *plugins.Plugin) []string {
|
func (s *Service) Get(ctx context.Context, p *plugins.Plugin) ([]string, error) {
|
||||||
hostEnv := []string{
|
hostEnv := []string{
|
||||||
fmt.Sprintf("GF_VERSION=%s", s.cfg.BuildVersion),
|
fmt.Sprintf("GF_VERSION=%s", s.cfg.BuildVersion),
|
||||||
}
|
}
|
||||||
@ -46,13 +46,23 @@ func (s *Service) Get(_ context.Context, p *plugins.Plugin) []string {
|
|||||||
hostEnv = append(hostEnv, s.license.Environment()...)
|
hostEnv = append(hostEnv, s.license.Environment()...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if p.ExternalService != nil {
|
||||||
|
hostEnv = append(
|
||||||
|
hostEnv,
|
||||||
|
fmt.Sprintf("GF_APP_URL=%s", s.cfg.GrafanaAppURL),
|
||||||
|
fmt.Sprintf("GF_PLUGIN_APP_CLIENT_ID=%s", p.ExternalService.ClientID),
|
||||||
|
fmt.Sprintf("GF_PLUGIN_APP_CLIENT_SECRET=%s", p.ExternalService.ClientSecret),
|
||||||
|
fmt.Sprintf("GF_PLUGIN_APP_PRIVATE_KEY=%s", p.ExternalService.PrivateKey),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
hostEnv = append(hostEnv, s.awsEnvVars()...)
|
hostEnv = append(hostEnv, s.awsEnvVars()...)
|
||||||
hostEnv = append(hostEnv, s.secureSocksProxyEnvVars()...)
|
hostEnv = append(hostEnv, s.secureSocksProxyEnvVars()...)
|
||||||
hostEnv = append(hostEnv, azsettings.WriteToEnvStr(s.cfg.Azure)...)
|
hostEnv = append(hostEnv, azsettings.WriteToEnvStr(s.cfg.Azure)...)
|
||||||
hostEnv = append(hostEnv, s.tracingEnvVars(p)...)
|
hostEnv = append(hostEnv, s.tracingEnvVars(p)...)
|
||||||
|
|
||||||
ev := getPluginSettings(p.ID, s.cfg).asEnvVar("GF_PLUGIN", hostEnv)
|
ev := getPluginSettings(p.ID, s.cfg).asEnvVar("GF_PLUGIN", hostEnv)
|
||||||
return ev
|
return ev, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) tracingEnvVars(plugin *plugins.Plugin) []string {
|
func (s *Service) tracingEnvVars(plugin *plugins.Plugin) []string {
|
||||||
|
@ -11,6 +11,8 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/plugins"
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
"github.com/grafana/grafana/pkg/plugins/config"
|
"github.com/grafana/grafana/pkg/plugins/config"
|
||||||
"github.com/grafana/grafana/pkg/plugins/manager/fakes"
|
"github.com/grafana/grafana/pkg/plugins/manager/fakes"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins/oauth"
|
||||||
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -37,7 +39,8 @@ func TestInitializer_envVars(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}, licensing)
|
}, licensing)
|
||||||
|
|
||||||
envVars := envVarsProvider.Get(context.Background(), p)
|
envVars, err := envVarsProvider.Get(context.Background(), p)
|
||||||
|
require.NoError(t, err)
|
||||||
assert.Len(t, envVars, 6)
|
assert.Len(t, envVars, 6)
|
||||||
assert.Equal(t, "GF_PLUGIN_CUSTOM_ENV_VAR=customVal", envVars[0])
|
assert.Equal(t, "GF_PLUGIN_CUSTOM_ENV_VAR=customVal", envVars[0])
|
||||||
assert.Equal(t, "GF_VERSION=", envVars[1])
|
assert.Equal(t, "GF_VERSION=", envVars[1])
|
||||||
@ -297,8 +300,39 @@ func TestInitializer_tracingEnvironmentVariables(t *testing.T) {
|
|||||||
} {
|
} {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
envVarsProvider := NewProvider(tc.cfg, nil)
|
envVarsProvider := NewProvider(tc.cfg, nil)
|
||||||
envVars := envVarsProvider.Get(context.Background(), tc.plugin)
|
envVars, err := envVarsProvider.Get(context.Background(), tc.plugin)
|
||||||
|
require.NoError(t, err)
|
||||||
tc.exp(t, envVars)
|
tc.exp(t, envVars)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestInitializer_oauthEnvVars(t *testing.T) {
|
||||||
|
t.Run("backend datasource with oauth registration", func(t *testing.T) {
|
||||||
|
p := &plugins.Plugin{
|
||||||
|
JSONData: plugins.JSONData{
|
||||||
|
ID: "test",
|
||||||
|
ExternalServiceRegistration: &oauth.ExternalServiceRegistration{},
|
||||||
|
},
|
||||||
|
ExternalService: &oauth.ExternalService{
|
||||||
|
ClientID: "clientID",
|
||||||
|
ClientSecret: "clientSecret",
|
||||||
|
PrivateKey: "privatePem",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
envVarsProvider := NewProvider(&config.Cfg{
|
||||||
|
GrafanaAppURL: "https://myorg.com/",
|
||||||
|
Features: featuremgmt.WithFeatures(featuremgmt.FlagExternalServiceAuth),
|
||||||
|
}, nil)
|
||||||
|
envVars, err := envVarsProvider.Get(context.Background(), p)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, envVars, 5)
|
||||||
|
assert.Equal(t, "GF_VERSION=", envVars[0])
|
||||||
|
assert.Equal(t, "GF_APP_URL=https://myorg.com/", envVars[1])
|
||||||
|
assert.Equal(t, "GF_PLUGIN_APP_CLIENT_ID=clientID", envVars[2])
|
||||||
|
assert.Equal(t, "GF_PLUGIN_APP_CLIENT_SECRET=clientSecret", envVars[3])
|
||||||
|
assert.Equal(t, "GF_PLUGIN_APP_PRIVATE_KEY=privatePem", envVars[4])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/plugins"
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
"github.com/grafana/grafana/pkg/plugins/backendplugin"
|
"github.com/grafana/grafana/pkg/plugins/backendplugin"
|
||||||
"github.com/grafana/grafana/pkg/plugins/log"
|
"github.com/grafana/grafana/pkg/plugins/log"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins/oauth"
|
||||||
"github.com/grafana/grafana/pkg/plugins/repo"
|
"github.com/grafana/grafana/pkg/plugins/repo"
|
||||||
"github.com/grafana/grafana/pkg/plugins/storage"
|
"github.com/grafana/grafana/pkg/plugins/storage"
|
||||||
)
|
)
|
||||||
@ -422,3 +423,11 @@ func (f *FakePluginFileStore) File(ctx context.Context, pluginID, filename strin
|
|||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FakeOauthService struct {
|
||||||
|
Result *oauth.ExternalService
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FakeOauthService) RegisterExternalService(ctx context.Context, name string, svc *oauth.ExternalServiceRegistration) (*oauth.ExternalService, error) {
|
||||||
|
return f.Result, nil
|
||||||
|
}
|
||||||
|
@ -28,7 +28,10 @@ func (i *Initializer) Initialize(ctx context.Context, p *plugins.Plugin) error {
|
|||||||
return errors.New("could not find backend factory for plugin")
|
return errors.New("could not find backend factory for plugin")
|
||||||
}
|
}
|
||||||
|
|
||||||
env := i.envVarProvider.Get(ctx, p)
|
env, err := i.envVarProvider.Get(ctx, p)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if backendClient, err := backendFactory(p.ID, p.Logger(), env); err != nil {
|
if backendClient, err := backendFactory(p.ID, p.Logger(), env); err != nil {
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
|
@ -138,9 +138,9 @@ type fakeEnvVarsProvider struct {
|
|||||||
GetFunc func(ctx context.Context, p *plugins.Plugin) []string
|
GetFunc func(ctx context.Context, p *plugins.Plugin) []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fakeEnvVarsProvider) Get(ctx context.Context, p *plugins.Plugin) []string {
|
func (f *fakeEnvVarsProvider) Get(ctx context.Context, p *plugins.Plugin) ([]string, error) {
|
||||||
if f.GetFunc != nil {
|
if f.GetFunc != nil {
|
||||||
return f.GetFunc(ctx, p)
|
return f.GetFunc(ctx, p), nil
|
||||||
}
|
}
|
||||||
return nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -20,22 +20,25 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/plugins/manager/process"
|
"github.com/grafana/grafana/pkg/plugins/manager/process"
|
||||||
"github.com/grafana/grafana/pkg/plugins/manager/registry"
|
"github.com/grafana/grafana/pkg/plugins/manager/registry"
|
||||||
"github.com/grafana/grafana/pkg/plugins/manager/signature"
|
"github.com/grafana/grafana/pkg/plugins/manager/signature"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins/oauth"
|
||||||
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/util"
|
"github.com/grafana/grafana/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ plugins.ErrorResolver = (*Loader)(nil)
|
var _ plugins.ErrorResolver = (*Loader)(nil)
|
||||||
|
|
||||||
type Loader struct {
|
type Loader struct {
|
||||||
pluginFinder finder.Finder
|
pluginFinder finder.Finder
|
||||||
processManager process.Service
|
processManager process.Service
|
||||||
pluginRegistry registry.Service
|
pluginRegistry registry.Service
|
||||||
roleRegistry plugins.RoleRegistry
|
roleRegistry plugins.RoleRegistry
|
||||||
pluginInitializer initializer.Initializer
|
pluginInitializer initializer.Initializer
|
||||||
signatureValidator signature.Validator
|
signatureValidator signature.Validator
|
||||||
signatureCalculator plugins.SignatureCalculator
|
signatureCalculator plugins.SignatureCalculator
|
||||||
assetPath *assetpath.Service
|
externalServiceRegistry oauth.ExternalServiceRegistry
|
||||||
log log.Logger
|
assetPath *assetpath.Service
|
||||||
cfg *config.Cfg
|
log log.Logger
|
||||||
|
cfg *config.Cfg
|
||||||
|
|
||||||
angularInspector angularinspector.Inspector
|
angularInspector angularinspector.Inspector
|
||||||
|
|
||||||
@ -45,29 +48,30 @@ type Loader struct {
|
|||||||
func ProvideService(cfg *config.Cfg, license plugins.Licensing, authorizer plugins.PluginLoaderAuthorizer,
|
func ProvideService(cfg *config.Cfg, license plugins.Licensing, authorizer plugins.PluginLoaderAuthorizer,
|
||||||
pluginRegistry registry.Service, backendProvider plugins.BackendFactoryProvider, pluginFinder finder.Finder,
|
pluginRegistry registry.Service, backendProvider plugins.BackendFactoryProvider, pluginFinder finder.Finder,
|
||||||
roleRegistry plugins.RoleRegistry, assetPath *assetpath.Service, signatureCalculator plugins.SignatureCalculator,
|
roleRegistry plugins.RoleRegistry, assetPath *assetpath.Service, signatureCalculator plugins.SignatureCalculator,
|
||||||
angularInspector angularinspector.Inspector) *Loader {
|
angularInspector angularinspector.Inspector, externalServiceRegistry oauth.ExternalServiceRegistry) *Loader {
|
||||||
return New(cfg, license, authorizer, pluginRegistry, backendProvider, process.NewManager(pluginRegistry),
|
return New(cfg, license, authorizer, pluginRegistry, backendProvider, process.NewManager(pluginRegistry),
|
||||||
roleRegistry, assetPath, pluginFinder, signatureCalculator, angularInspector)
|
roleRegistry, assetPath, pluginFinder, signatureCalculator, angularInspector, externalServiceRegistry)
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(cfg *config.Cfg, license plugins.Licensing, authorizer plugins.PluginLoaderAuthorizer,
|
func New(cfg *config.Cfg, license plugins.Licensing, authorizer plugins.PluginLoaderAuthorizer,
|
||||||
pluginRegistry registry.Service, backendProvider plugins.BackendFactoryProvider,
|
pluginRegistry registry.Service, backendProvider plugins.BackendFactoryProvider,
|
||||||
processManager process.Service, roleRegistry plugins.RoleRegistry,
|
processManager process.Service, roleRegistry plugins.RoleRegistry,
|
||||||
assetPath *assetpath.Service, pluginFinder finder.Finder, signatureCalculator plugins.SignatureCalculator,
|
assetPath *assetpath.Service, pluginFinder finder.Finder, signatureCalculator plugins.SignatureCalculator,
|
||||||
angularInspector angularinspector.Inspector) *Loader {
|
angularInspector angularinspector.Inspector, externalServiceRegistry oauth.ExternalServiceRegistry) *Loader {
|
||||||
return &Loader{
|
return &Loader{
|
||||||
pluginFinder: pluginFinder,
|
pluginFinder: pluginFinder,
|
||||||
pluginRegistry: pluginRegistry,
|
pluginRegistry: pluginRegistry,
|
||||||
pluginInitializer: initializer.New(cfg, backendProvider, license),
|
pluginInitializer: initializer.New(cfg, backendProvider, license),
|
||||||
signatureValidator: signature.NewValidator(authorizer),
|
signatureValidator: signature.NewValidator(authorizer),
|
||||||
signatureCalculator: signatureCalculator,
|
signatureCalculator: signatureCalculator,
|
||||||
processManager: processManager,
|
processManager: processManager,
|
||||||
errs: make(map[string]*plugins.SignatureError),
|
errs: make(map[string]*plugins.SignatureError),
|
||||||
log: log.New("plugin.loader"),
|
log: log.New("plugin.loader"),
|
||||||
roleRegistry: roleRegistry,
|
roleRegistry: roleRegistry,
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
assetPath: assetPath,
|
assetPath: assetPath,
|
||||||
angularInspector: angularInspector,
|
angularInspector: angularInspector,
|
||||||
|
externalServiceRegistry: externalServiceRegistry,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,6 +206,15 @@ func (l *Loader) loadPlugins(ctx context.Context, src plugins.PluginSource, foun
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if p.ExternalServiceRegistration != nil && l.cfg.Features.IsEnabled(featuremgmt.FlagExternalServiceAuth) {
|
||||||
|
s, err := l.externalServiceRegistry.RegisterExternalService(ctx, p.ID, p.ExternalServiceRegistration)
|
||||||
|
if err != nil {
|
||||||
|
l.log.Error("Could not register an external service. Initialization skipped", "pluginID", p.ID, "err", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
p.ExternalService = s
|
||||||
|
}
|
||||||
|
|
||||||
err := l.pluginInitializer.Initialize(ctx, p)
|
err := l.pluginInitializer.Initialize(ctx, p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.log.Error("Could not initialize plugin", "pluginId", p.ID, "err", err)
|
l.log.Error("Could not initialize plugin", "pluginId", p.ID, "err", err)
|
||||||
|
@ -1443,7 +1443,7 @@ func newLoader(t *testing.T, cfg *config.Cfg, cbs ...func(loader *Loader)) *Load
|
|||||||
l := New(cfg, &fakes.FakeLicensingService{}, signature.NewUnsignedAuthorizer(cfg), fakes.NewFakePluginRegistry(),
|
l := New(cfg, &fakes.FakeLicensingService{}, signature.NewUnsignedAuthorizer(cfg), fakes.NewFakePluginRegistry(),
|
||||||
fakes.NewFakeBackendProcessProvider(), fakes.NewFakeProcessManager(), fakes.NewFakeRoleRegistry(),
|
fakes.NewFakeBackendProcessProvider(), fakes.NewFakeProcessManager(), fakes.NewFakeRoleRegistry(),
|
||||||
assetpath.ProvideService(pluginscdn.ProvideService(cfg)), finder.NewLocalFinder(cfg),
|
assetpath.ProvideService(pluginscdn.ProvideService(cfg)), finder.NewLocalFinder(cfg),
|
||||||
signature.ProvideService(cfg, statickey.New()), angularInspector)
|
signature.ProvideService(cfg, statickey.New()), angularInspector, &fakes.FakeOauthService{})
|
||||||
|
|
||||||
for _, cb := range cbs {
|
for _, cb := range cbs {
|
||||||
cb(l)
|
cb(l)
|
||||||
|
@ -123,7 +123,7 @@ func TestIntegrationPluginManager(t *testing.T) {
|
|||||||
l := loader.ProvideService(pCfg, lic, signature.NewUnsignedAuthorizer(pCfg),
|
l := loader.ProvideService(pCfg, lic, signature.NewUnsignedAuthorizer(pCfg),
|
||||||
reg, provider.ProvideService(coreRegistry), finder.NewLocalFinder(pCfg), fakes.NewFakeRoleRegistry(),
|
reg, provider.ProvideService(coreRegistry), finder.NewLocalFinder(pCfg), fakes.NewFakeRoleRegistry(),
|
||||||
assetpath.ProvideService(pluginscdn.ProvideService(pCfg)), signature.ProvideService(pCfg, statickey.New()),
|
assetpath.ProvideService(pluginscdn.ProvideService(pCfg)), signature.ProvideService(pCfg, statickey.New()),
|
||||||
angularInspector)
|
angularInspector, &fakes.FakeOauthService{})
|
||||||
srcs := sources.ProvideService(cfg, pCfg)
|
srcs := sources.ProvideService(cfg, pCfg)
|
||||||
ps, err := store.ProvideService(reg, srcs, l)
|
ps, err := store.ProvideService(reg, srcs, l)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
37
pkg/plugins/oauth/models.go
Normal file
37
pkg/plugins/oauth/models.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package oauth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SelfCfg is a subset of oauthserver.SelfCfg making some fields optional
|
||||||
|
type SelfCfg struct {
|
||||||
|
Enabled *bool `json:"enabled,omitempty"`
|
||||||
|
Permissions []accesscontrol.Permission `json:"permissions,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImpersonationCfg is a subset of oauthserver.ImpersonationCfg making some fields optional
|
||||||
|
type ImpersonationCfg struct {
|
||||||
|
Enabled *bool `json:"enabled,omitempty"`
|
||||||
|
Groups *bool `json:"groups,omitempty"`
|
||||||
|
Permissions []accesscontrol.Permission `json:"permissions,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PluginExternalServiceRegistration is a subset of oauthserver.ExternalServiceRegistration
|
||||||
|
// simplified for the plugin use case.
|
||||||
|
type ExternalServiceRegistration struct {
|
||||||
|
Impersonation *ImpersonationCfg `json:"impersonation,omitempty"`
|
||||||
|
Self *SelfCfg `json:"self,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExternalService struct {
|
||||||
|
ClientID string `json:"clientId"`
|
||||||
|
ClientSecret string `json:"clientSecret"`
|
||||||
|
PrivateKey string `json:"privateKey"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExternalServiceRegistry interface {
|
||||||
|
RegisterExternalService(ctx context.Context, name string, svc *ExternalServiceRegistration) (*ExternalService, error)
|
||||||
|
}
|
@ -17,6 +17,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/plugins/backendplugin/pluginextensionv2"
|
"github.com/grafana/grafana/pkg/plugins/backendplugin/pluginextensionv2"
|
||||||
"github.com/grafana/grafana/pkg/plugins/backendplugin/secretsmanagerplugin"
|
"github.com/grafana/grafana/pkg/plugins/backendplugin/secretsmanagerplugin"
|
||||||
"github.com/grafana/grafana/pkg/plugins/log"
|
"github.com/grafana/grafana/pkg/plugins/log"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins/oauth"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/grafana/grafana/pkg/util"
|
"github.com/grafana/grafana/pkg/util"
|
||||||
)
|
)
|
||||||
@ -53,6 +54,8 @@ type Plugin struct {
|
|||||||
|
|
||||||
AngularDetected bool
|
AngularDetected bool
|
||||||
|
|
||||||
|
ExternalService *oauth.ExternalService
|
||||||
|
|
||||||
Renderer pluginextensionv2.RendererPlugin
|
Renderer pluginextensionv2.RendererPlugin
|
||||||
SecretsManager secretsmanagerplugin.SecretsManagerPlugin
|
SecretsManager secretsmanagerplugin.SecretsManagerPlugin
|
||||||
client backendplugin.Plugin
|
client backendplugin.Plugin
|
||||||
@ -150,6 +153,9 @@ type JSONData struct {
|
|||||||
|
|
||||||
// Backend (Datasource + Renderer + SecretsManager)
|
// Backend (Datasource + Renderer + SecretsManager)
|
||||||
Executable string `json:"executable,omitempty"`
|
Executable string `json:"executable,omitempty"`
|
||||||
|
|
||||||
|
// Oauth App Service Registration
|
||||||
|
ExternalServiceRegistration *oauth.ExternalServiceRegistration `json:"externalServiceRegistration,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadPluginJSON(reader io.Reader) (JSONData, error) {
|
func ReadPluginJSON(reader io.Reader) (JSONData, error) {
|
||||||
|
@ -33,7 +33,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/oauthserver/store"
|
"github.com/grafana/grafana/pkg/services/oauthserver/store"
|
||||||
"github.com/grafana/grafana/pkg/services/oauthserver/utils"
|
"github.com/grafana/grafana/pkg/services/oauthserver/utils"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/grafana/grafana/pkg/services/secrets/kvstore"
|
|
||||||
"github.com/grafana/grafana/pkg/services/serviceaccounts"
|
"github.com/grafana/grafana/pkg/services/serviceaccounts"
|
||||||
"github.com/grafana/grafana/pkg/services/signingkeys"
|
"github.com/grafana/grafana/pkg/services/signingkeys"
|
||||||
"github.com/grafana/grafana/pkg/services/team"
|
"github.com/grafana/grafana/pkg/services/team"
|
||||||
@ -62,7 +61,7 @@ type OAuth2ServiceImpl struct {
|
|||||||
publicKey interface{}
|
publicKey interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProvideService(router routing.RouteRegister, db db.DB, cfg *setting.Cfg, skv kvstore.SecretsKVStore,
|
func ProvideService(router routing.RouteRegister, db db.DB, cfg *setting.Cfg,
|
||||||
svcAccSvc serviceaccounts.Service, accessControl ac.AccessControl, acSvc ac.Service, userSvc user.Service,
|
svcAccSvc serviceaccounts.Service, accessControl ac.AccessControl, acSvc ac.Service, userSvc user.Service,
|
||||||
teamSvc team.Service, keySvc signingkeys.Service, fmgmt *featuremgmt.FeatureManager) (*OAuth2ServiceImpl, error) {
|
teamSvc team.Service, keySvc signingkeys.Service, fmgmt *featuremgmt.FeatureManager) (*OAuth2ServiceImpl, error) {
|
||||||
if !fmgmt.IsEnabled(featuremgmt.FlagExternalServiceAuth) {
|
if !fmgmt.IsEnabled(featuremgmt.FlagExternalServiceAuth) {
|
||||||
|
@ -39,6 +39,7 @@ func ProvideConfig(settingProvider setting.Provider, grafanaCfg *setting.Cfg, fe
|
|||||||
grafanaCfg.BuildVersion,
|
grafanaCfg.BuildVersion,
|
||||||
grafanaCfg.PluginLogBackendRequests,
|
grafanaCfg.PluginLogBackendRequests,
|
||||||
grafanaCfg.PluginsCDNURLTemplate,
|
grafanaCfg.PluginsCDNURLTemplate,
|
||||||
|
grafanaCfg.AppURL,
|
||||||
tracingCfg,
|
tracingCfg,
|
||||||
featuremgmt.ProvideToggles(features),
|
featuremgmt.ProvideToggles(features),
|
||||||
grafanaCfg.AngularSupportEnabled,
|
grafanaCfg.AngularSupportEnabled,
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/plugins/manager/signature"
|
"github.com/grafana/grafana/pkg/plugins/manager/signature"
|
||||||
"github.com/grafana/grafana/pkg/plugins/manager/sources"
|
"github.com/grafana/grafana/pkg/plugins/manager/sources"
|
||||||
"github.com/grafana/grafana/pkg/plugins/manager/store"
|
"github.com/grafana/grafana/pkg/plugins/manager/store"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins/oauth"
|
||||||
"github.com/grafana/grafana/pkg/plugins/pluginscdn"
|
"github.com/grafana/grafana/pkg/plugins/pluginscdn"
|
||||||
"github.com/grafana/grafana/pkg/plugins/repo"
|
"github.com/grafana/grafana/pkg/plugins/repo"
|
||||||
"github.com/grafana/grafana/pkg/services/caching"
|
"github.com/grafana/grafana/pkg/services/caching"
|
||||||
@ -35,6 +36,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
|
||||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings"
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings"
|
||||||
pluginSettings "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings/service"
|
pluginSettings "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings/service"
|
||||||
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/serviceregistration"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -80,6 +82,8 @@ var WireSet = wire.NewSet(
|
|||||||
wire.Bind(new(plugins.KeyRetriever), new(*keyretriever.Service)),
|
wire.Bind(new(plugins.KeyRetriever), new(*keyretriever.Service)),
|
||||||
keyretriever.ProvideService,
|
keyretriever.ProvideService,
|
||||||
dynamic.ProvideService,
|
dynamic.ProvideService,
|
||||||
|
serviceregistration.ProvideService,
|
||||||
|
wire.Bind(new(oauth.ExternalServiceRegistry), new(*serviceregistration.Service)),
|
||||||
)
|
)
|
||||||
|
|
||||||
// WireExtensionSet provides a wire.ProviderSet of plugin providers that can be
|
// WireExtensionSet provides a wire.ProviderSet of plugin providers that can be
|
||||||
|
@ -0,0 +1,62 @@
|
|||||||
|
package serviceregistration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/plugins/oauth"
|
||||||
|
"github.com/grafana/grafana/pkg/services/oauthserver"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
os oauthserver.OAuth2Server
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProvideService(os oauthserver.OAuth2Server) *Service {
|
||||||
|
s := &Service{
|
||||||
|
os: os,
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterExternalService is a simplified wrapper around SaveExternalService for the plugin use case.
|
||||||
|
func (s *Service) RegisterExternalService(ctx context.Context, svcName string, svc *oauth.ExternalServiceRegistration) (*oauth.ExternalService, error) {
|
||||||
|
impersonation := oauthserver.ImpersonationCfg{}
|
||||||
|
if svc.Impersonation != nil {
|
||||||
|
impersonation.Permissions = svc.Impersonation.Permissions
|
||||||
|
if svc.Impersonation.Enabled != nil {
|
||||||
|
impersonation.Enabled = *svc.Impersonation.Enabled
|
||||||
|
} else {
|
||||||
|
impersonation.Enabled = true
|
||||||
|
}
|
||||||
|
if svc.Impersonation.Groups != nil {
|
||||||
|
impersonation.Groups = *svc.Impersonation.Groups
|
||||||
|
} else {
|
||||||
|
impersonation.Groups = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self := oauthserver.SelfCfg{}
|
||||||
|
if svc.Self != nil {
|
||||||
|
self.Permissions = svc.Self.Permissions
|
||||||
|
if svc.Self.Enabled != nil {
|
||||||
|
self.Enabled = *svc.Self.Enabled
|
||||||
|
} else {
|
||||||
|
self.Enabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
extSvc, err := s.os.SaveExternalService(ctx, &oauthserver.ExternalServiceRegistration{
|
||||||
|
Name: svcName,
|
||||||
|
Impersonation: impersonation,
|
||||||
|
Self: self,
|
||||||
|
Key: &oauthserver.KeyOption{Generate: true},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &oauth.ExternalService{
|
||||||
|
ClientID: extSvc.ID,
|
||||||
|
ClientSecret: extSvc.Secret,
|
||||||
|
PrivateKey: extSvc.KeyResult.PrivatePem,
|
||||||
|
}, nil
|
||||||
|
}
|
Reference in New Issue
Block a user