AuthN: Set oauth client grant_types based on plugin state (#77248)

* Disable plugin service account

* Fix bug seen by linoman 💯

Co-authored-by: linoman <2051016+linoman@users.noreply.github.com>

* Account for PR feedback

Co-authored-by: linoman <2051016+linoman@users.noreply.github.com>

* Fix test data

* Enable datasource plugins by default

Co-authored-by: Andres Martinez Gotor <andres.martinez@grafana.com>

* Update pkg/services/extsvcauth/oauthserver/oasimpl/service.go

* Handle error differently

* Fix service reg

---------

Co-authored-by: linoman <2051016+linoman@users.noreply.github.com>
Co-authored-by: Andres Martinez Gotor <andres.martinez@grafana.com>
This commit is contained in:
Gabriel MABILLE 2023-10-27 14:45:04 +02:00 committed by GitHub
parent 214535c1a9
commit 83e9088314
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 226 additions and 77 deletions

View File

@ -19,7 +19,6 @@
},
"externalServiceRegistration": {
"impersonation": {
"enabled" : true,
"groups" : true,
"permissions" : [
{

View File

@ -425,9 +425,6 @@ schemas: [{
}
#Impersonation: {
// Enabled allows the service to request access tokens to impersonate users using the jwtbearer grant
// Defaults to true.
enabled?: bool
// Groups allows the service to list the impersonated user's teams.
// Defaults to true.
groups?: bool

View File

@ -140,10 +140,6 @@ type Header struct {
// Impersonation defines model for Impersonation.
type Impersonation struct {
// Enabled allows the service to request access tokens to impersonate users using the jwtbearer grant
// Defaults to true.
Enabled *bool `json:"enabled,omitempty"`
// Groups allows the service to list the impersonated user's teams.
// Defaults to true.
Groups *bool `json:"groups,omitempty"`

View File

@ -283,7 +283,7 @@ func TestExtendedJWT_Authenticate(t *testing.T) {
Scopes: []string{"profile", "groups"},
},
initTestEnv: func(env *testEnv) {
env.oauthSvc.ExpectedErr = oauthserver.ErrClientNotFound("unknown-client-id")
env.oauthSvc.ExpectedErr = oauthserver.ErrClientNotFoundFn("unknown-client-id")
},
orgID: 1,
want: nil,

View File

@ -1,8 +1,6 @@
package oauthserver
import (
"fmt"
"github.com/grafana/grafana/pkg/util/errutil"
)
@ -17,11 +15,11 @@ var (
ErrClientRequiredName = errutil.BadRequest(
"oauthserver.required-client-name",
errutil.WithPublicMessage("client name is required")).Errorf("Client name is required")
ErrClientNotFound = errutil.NotFound(
ErrClientNotFoundMessageID,
errutil.WithPublicMessage("Requested client has not been found"))
)
func ErrClientNotFound(clientID string) error {
return errutil.NotFound(
ErrClientNotFoundMessageID,
errutil.WithPublicMessage(fmt.Sprintf("Client '%s' not found", clientID))).
Errorf("client '%s' not found", clientID)
func ErrClientNotFoundFn(clientID string) error {
return ErrClientNotFound.Errorf("client '%s' not found", clientID)
}

View File

@ -42,12 +42,13 @@ type OAuth2Server interface {
HandleIntrospectionRequest(rw http.ResponseWriter, req *http.Request)
}
//go:generate mockery --name Store --structname MockStore --outpkg oauthtest --filename store_mock.go --output ./oauthtest/
//go:generate mockery --name Store --structname MockStore --outpkg oastest --filename store_mock.go --output ./oastest/
type Store interface {
RegisterExternalService(ctx context.Context, client *OAuthExternalService) error
SaveExternalService(ctx context.Context, client *OAuthExternalService) error
GetExternalService(ctx context.Context, id string) (*OAuthExternalService, error)
GetExternalServiceByName(ctx context.Context, name string) (*OAuthExternalService, error)
GetExternalServicePublicKey(ctx context.Context, clientID string) (*jose.JSONWebKey, error)
RegisterExternalService(ctx context.Context, client *OAuthExternalService) error
SaveExternalService(ctx context.Context, client *OAuthExternalService) error
UpdateExternalServiceGrantTypes(ctx context.Context, clientID, grantTypes string) error
}

View File

@ -46,7 +46,7 @@ func TestOAuth2ServiceImpl_GetPublicKeyScopes(t *testing.T) {
{
name: "should error out when GetExternalService returns error",
initTestEnv: func(env *TestEnv) {
env.OAuthStore.On("GetExternalService", mock.Anything, mock.Anything).Return(nil, oauthserver.ErrClientNotFound("my-ext-service"))
env.OAuthStore.On("GetExternalService", mock.Anything, mock.Anything).Return(nil, oauthserver.ErrClientNotFoundFn("my-ext-service"))
},
wantErr: true,
},

View File

@ -22,6 +22,7 @@ import (
"golang.org/x/crypto/bcrypt"
"github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/infra/localcache"
"github.com/grafana/grafana/pkg/infra/log"
@ -33,12 +34,12 @@ import (
"github.com/grafana/grafana/pkg/services/extsvcauth/oauthserver/store"
"github.com/grafana/grafana/pkg/services/extsvcauth/oauthserver/utils"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings"
"github.com/grafana/grafana/pkg/services/serviceaccounts"
"github.com/grafana/grafana/pkg/services/signingkeys"
"github.com/grafana/grafana/pkg/services/team"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util/errutil"
)
const (
@ -61,7 +62,7 @@ type OAuth2ServiceImpl struct {
publicKey any
}
func ProvideService(router routing.RouteRegister, db db.DB, cfg *setting.Cfg,
func ProvideService(router routing.RouteRegister, bus bus.Bus, db db.DB, cfg *setting.Cfg,
extSvcAccSvc serviceaccounts.ExtSvcAccountsService, accessControl ac.AccessControl, acSvc ac.Service, userSvc user.Service,
teamSvc team.Service, keySvc signingkeys.Service, fmgmt *featuremgmt.FeatureManager) (*OAuth2ServiceImpl, error) {
if !fmgmt.IsEnabled(featuremgmt.FlagExternalServiceAuth) {
@ -91,6 +92,8 @@ func ProvideService(router routing.RouteRegister, db db.DB, cfg *setting.Cfg,
api := api.NewAPI(router, s)
api.RegisterAPIEndpoints()
bus.AddEventListener(s.handlePluginStateChanged)
s.oauthProvider = newProvider(config, s, keySvc)
return s, nil
@ -134,44 +137,50 @@ func (s *OAuth2ServiceImpl) GetExternalService(ctx context.Context, id string) (
return nil, err
}
// Handle the case where the external service has no service account
if err := s.setClientUser(ctx, client); err != nil {
return nil, err
}
s.cache.Set(id, *client, cacheExpirationTime)
return client, nil
}
// setClientUser sets the SignedInUser and SelfPermissions fields of the client
func (s *OAuth2ServiceImpl) setClientUser(ctx context.Context, client *oauthserver.OAuthExternalService) error {
if client.ServiceAccountID == oauthserver.NoServiceAccountID {
s.logger.Debug("GetExternalService: service has no service account, hence no permission", "id", id, "name", client.Name)
// Create a signed in user with no role and no permissions
s.logger.Debug("GetExternalService: service has no service account, hence no permission", "client_id", client.ClientID, "name", client.Name)
// Create a signed in user with no role and no permission
client.SignedInUser = &user.SignedInUser{
UserID: oauthserver.NoServiceAccountID,
OrgID: oauthserver.TmpOrgID,
Name: client.Name,
Permissions: map[int64]map[string][]string{oauthserver.TmpOrgID: {}},
}
s.cache.Set(id, *client, cacheExpirationTime)
return client, nil
return nil
}
// Retrieve self permissions and generate a signed in user
s.logger.Debug("GetExternalService: fetch permissions", "client id", id)
s.logger.Debug("GetExternalService: fetch permissions", "client_id", client.ClientID)
sa, err := s.saService.RetrieveExtSvcAccount(ctx, oauthserver.TmpOrgID, client.ServiceAccountID)
if err != nil {
s.logger.Error("GetExternalService: error fetching service account", "id", id, "error", err)
return nil, err
s.logger.Error("GetExternalService: error fetching service account", "id", client.ClientID, "error", err)
return err
}
client.SignedInUser = &user.SignedInUser{
UserID: sa.ID,
OrgID: oauthserver.TmpOrgID,
OrgRole: sa.Role, // Need this to compute the permissions in OSS
OrgRole: sa.Role,
Login: sa.Login,
Name: sa.Name,
Permissions: map[int64]map[string][]string{},
}
client.SelfPermissions, err = s.acService.GetUserPermissions(ctx, client.SignedInUser, ac.Options{})
if err != nil {
s.logger.Error("GetExternalService: error fetching permissions", "id", id, "error", err)
return nil, err
s.logger.Error("GetExternalService: error fetching permissions", "client_id", client.ClientID, "error", err)
return err
}
client.SignedInUser.Permissions[oauthserver.TmpOrgID] = ac.GroupScopesByAction(client.SelfPermissions)
s.cache.Set(id, *client, cacheExpirationTime)
return client, nil
return nil
}
// SaveExternalService creates or updates an external service in the database, it generates client_id and secrets and
@ -186,14 +195,9 @@ func (s *OAuth2ServiceImpl) SaveExternalService(ctx context.Context, registratio
// Check if the client already exists in store
client, errFetchExtSvc := s.sqlstore.GetExternalServiceByName(ctx, registration.Name)
if errFetchExtSvc != nil {
var srcError errutil.Error
if errors.As(errFetchExtSvc, &srcError) {
if srcError.MessageID != oauthserver.ErrClientNotFoundMessageID {
s.logger.Error("Error fetching service", "external service", registration.Name, "error", errFetchExtSvc)
return nil, errFetchExtSvc
}
}
if errFetchExtSvc != nil && !errors.Is(errFetchExtSvc, oauthserver.ErrClientNotFound) {
s.logger.Error("Error fetching service", "external service", registration.Name, "error", errFetchExtSvc)
return nil, errFetchExtSvc
}
// Otherwise, create a new client
if client == nil {
@ -386,13 +390,10 @@ func (s *OAuth2ServiceImpl) handleKeyOptions(ctx context.Context, keyOption *ext
// handleRegistrationPermissions parses the registration form to retrieve requested permissions and adds default
// permissions when impersonation is requested
func (*OAuth2ServiceImpl) handleRegistrationPermissions(registration *extsvcauth.ExternalServiceRegistration) ([]ac.Permission, []ac.Permission) {
selfPermissions := []ac.Permission{}
selfPermissions := registration.Self.Permissions
impersonatePermissions := []ac.Permission{}
if registration.Self.Enabled {
selfPermissions = append(selfPermissions, registration.Self.Permissions...)
}
if registration.Impersonation.Enabled {
if len(registration.Impersonation.Permissions) > 0 {
requiredForToken := []ac.Permission{
{Action: ac.ActionUsersRead, Scope: oauthserver.ScopeGlobalUsersSelf},
{Action: ac.ActionUsersPermissionsRead, Scope: oauthserver.ScopeUsersSelf},
@ -405,3 +406,42 @@ func (*OAuth2ServiceImpl) handleRegistrationPermissions(registration *extsvcauth
}
return selfPermissions, impersonatePermissions
}
// handlePluginStateChanged reset the client authorized grant_types according to the plugin state
func (s *OAuth2ServiceImpl) handlePluginStateChanged(ctx context.Context, event *pluginsettings.PluginStateChangedEvent) error {
s.logger.Info("Plugin state changed", "pluginId", event.PluginId, "enabled", event.Enabled)
// Retrieve client associated to the plugin
slug := slugify.Slugify(event.PluginId)
client, err := s.sqlstore.GetExternalServiceByName(ctx, slug)
if err != nil {
if errors.Is(err, oauthserver.ErrClientNotFound) {
s.logger.Debug("No external service linked to this plugin", "pluginId", event.PluginId)
return nil
}
s.logger.Error("Error fetching service", "pluginId", event.PluginId, "error", err)
return err
}
// Since we will change the grants, clear cache entry
s.cache.Delete(client.ClientID)
if !event.Enabled {
// Plugin is disabled => remove all grant_types
return s.sqlstore.UpdateExternalServiceGrantTypes(ctx, client.ClientID, "")
}
if err := s.setClientUser(ctx, client); err != nil {
return err
}
// The plugin has self permissions (not only impersonate)
canOnlyImpersonate := len(client.SelfPermissions) == 1 && (client.SelfPermissions[0].Action == ac.ActionUsersImpersonate)
selfEnabled := len(client.SelfPermissions) > 0 && !canOnlyImpersonate
// The plugin declared impersonate permissions
impersonateEnabled := len(client.ImpersonatePermissions) > 0
grantTypes := s.computeGrantTypes(selfEnabled, impersonateEnabled)
return s.sqlstore.UpdateExternalServiceGrantTypes(ctx, client.ClientID, strings.Join(grantTypes, ","))
}

View File

@ -24,6 +24,8 @@ import (
"github.com/grafana/grafana/pkg/services/extsvcauth/oauthserver"
"github.com/grafana/grafana/pkg/services/extsvcauth/oauthserver/oastest"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings"
sa "github.com/grafana/grafana/pkg/services/serviceaccounts"
saTests "github.com/grafana/grafana/pkg/services/serviceaccounts/tests"
"github.com/grafana/grafana/pkg/services/signingkeys/signingkeystest"
@ -114,7 +116,7 @@ func TestOAuth2ServiceImpl_SaveExternalService(t *testing.T) {
name: "should create a new client without permissions",
init: func(env *TestEnv) {
// No client at the beginning
env.OAuthStore.On("GetExternalServiceByName", mock.Anything, mock.Anything).Return(nil, oauthserver.ErrClientNotFound(serviceName))
env.OAuthStore.On("GetExternalServiceByName", mock.Anything, mock.Anything).Return(nil, oauthserver.ErrClientNotFoundFn(serviceName))
env.OAuthStore.On("SaveExternalService", mock.Anything, mock.Anything).Return(nil)
// Return a service account ID
@ -139,7 +141,7 @@ func TestOAuth2ServiceImpl_SaveExternalService(t *testing.T) {
name: "should allow client credentials grant with correct permissions",
init: func(env *TestEnv) {
// No client at the beginning
env.OAuthStore.On("GetExternalServiceByName", mock.Anything, mock.Anything).Return(nil, oauthserver.ErrClientNotFound(serviceName))
env.OAuthStore.On("GetExternalServiceByName", mock.Anything, mock.Anything).Return(nil, oauthserver.ErrClientNotFoundFn(serviceName))
env.OAuthStore.On("SaveExternalService", mock.Anything, mock.Anything).Return(nil)
// Return a service account ID
@ -175,7 +177,7 @@ func TestOAuth2ServiceImpl_SaveExternalService(t *testing.T) {
name: "should allow jwt bearer grant and set default permissions",
init: func(env *TestEnv) {
// No client at the beginning
env.OAuthStore.On("GetExternalServiceByName", mock.Anything, mock.Anything).Return(nil, oauthserver.ErrClientNotFound(serviceName))
env.OAuthStore.On("GetExternalServiceByName", mock.Anything, mock.Anything).Return(nil, oauthserver.ErrClientNotFoundFn(serviceName))
env.OAuthStore.On("SaveExternalService", mock.Anything, mock.Anything).Return(nil)
// The service account needs to be created with a permission to impersonate users
env.SAService.On("ManageExtSvcAccount", mock.Anything, mock.Anything).Return(int64(10), nil)
@ -310,7 +312,7 @@ func TestOAuth2ServiceImpl_GetExternalService(t *testing.T) {
{
name: "should return error when the client was not found",
init: func(env *TestEnv) {
env.OAuthStore.On("GetExternalService", mock.Anything, mock.Anything).Return(nil, oauthserver.ErrClientNotFound(serviceName))
env.OAuthStore.On("GetExternalService", mock.Anything, mock.Anything).Return(nil, oauthserver.ErrClientNotFoundFn(serviceName))
},
wantErr: true,
},
@ -474,3 +476,105 @@ mgGaC8vUIigFQVsVB+v/HZ4yG1Rcvysig+tyNk1dZQpozpFc2dGmzHlGhw==
require.True(t, result.Generated)
})
}
func TestOAuth2ServiceImpl_handlePluginStateChanged(t *testing.T) {
pluginID := "my-app"
clientID := "RANDOMID"
impersonatePermission := []ac.Permission{{Action: ac.ActionUsersImpersonate, Scope: ac.ScopeUsersAll}}
selfPermission := append(impersonatePermission, ac.Permission{Action: ac.ActionUsersRead, Scope: ac.ScopeUsersAll})
saID := int64(101)
client := &oauthserver.OAuthExternalService{
ID: 11,
Name: pluginID,
ClientID: clientID,
Secret: "SECRET",
ServiceAccountID: saID,
}
clientWithImpersonate := &oauthserver.OAuthExternalService{
ID: 11,
Name: pluginID,
ClientID: clientID,
Secret: "SECRET",
ImpersonatePermissions: []ac.Permission{
{Action: ac.ActionUsersRead, Scope: ac.ScopeUsersAll},
},
ServiceAccountID: saID,
}
extSvcAcc := &sa.ExtSvcAccount{
ID: saID,
Login: "sa-my-app",
Name: pluginID,
OrgID: extsvcauth.TmpOrgID,
IsDisabled: false,
Role: org.RoleNone,
}
tests := []struct {
name string
init func(*TestEnv)
cmd *pluginsettings.PluginStateChangedEvent
}{
{
name: "should do nothing with not found",
init: func(te *TestEnv) {
te.OAuthStore.On("GetExternalServiceByName", mock.Anything, "unknown").Return(nil, oauthserver.ErrClientNotFoundFn("unknown"))
},
cmd: &pluginsettings.PluginStateChangedEvent{PluginId: "unknown", OrgId: 1, Enabled: false},
},
{
name: "should remove grants",
init: func(te *TestEnv) {
te.OAuthStore.On("GetExternalServiceByName", mock.Anything, pluginID).Return(clientWithImpersonate, nil)
te.OAuthStore.On("UpdateExternalServiceGrantTypes", mock.Anything, clientID, "").Return(nil)
},
cmd: &pluginsettings.PluginStateChangedEvent{PluginId: pluginID, OrgId: 1, Enabled: false},
},
{
name: "should set both grants",
init: func(te *TestEnv) {
te.OAuthStore.On("GetExternalServiceByName", mock.Anything, mock.Anything).Return(clientWithImpersonate, nil)
te.SAService.On("RetrieveExtSvcAccount", mock.Anything, extsvcauth.TmpOrgID, saID).Return(extSvcAcc, nil)
te.AcStore.On("GetUserPermissions", mock.Anything, mock.Anything, mock.Anything).Return(selfPermission, nil)
te.OAuthStore.On("UpdateExternalServiceGrantTypes", mock.Anything, clientID,
string(fosite.GrantTypeClientCredentials)+","+string(fosite.GrantTypeJWTBearer)).Return(nil)
},
cmd: &pluginsettings.PluginStateChangedEvent{PluginId: pluginID, OrgId: 1, Enabled: true},
},
{
name: "should set impersonate grant",
init: func(te *TestEnv) {
te.OAuthStore.On("GetExternalServiceByName", mock.Anything, mock.Anything).Return(clientWithImpersonate, nil)
te.SAService.On("RetrieveExtSvcAccount", mock.Anything, extsvcauth.TmpOrgID, saID).Return(extSvcAcc, nil)
te.AcStore.On("GetUserPermissions", mock.Anything, mock.Anything, mock.Anything).Return(impersonatePermission, nil)
te.OAuthStore.On("UpdateExternalServiceGrantTypes", mock.Anything, clientID, string(fosite.GrantTypeJWTBearer)).Return(nil)
},
cmd: &pluginsettings.PluginStateChangedEvent{PluginId: pluginID, OrgId: 1, Enabled: true},
},
{
name: "should set client_credentials grant",
init: func(te *TestEnv) {
te.OAuthStore.On("GetExternalServiceByName", mock.Anything, mock.Anything).Return(client, nil)
te.SAService.On("RetrieveExtSvcAccount", mock.Anything, extsvcauth.TmpOrgID, saID).Return(extSvcAcc, nil)
te.AcStore.On("GetUserPermissions", mock.Anything, mock.Anything, mock.Anything).Return(selfPermission, nil)
te.OAuthStore.On("UpdateExternalServiceGrantTypes", mock.Anything, clientID, string(fosite.GrantTypeClientCredentials)).Return(nil)
},
cmd: &pluginsettings.PluginStateChangedEvent{PluginId: pluginID, OrgId: 1, Enabled: true},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
env := setupTestEnv(t)
if tt.init != nil {
tt.init(env)
}
err := env.S.handlePluginStateChanged(context.Background(), tt.cmd)
require.NoError(t, err)
// Check that mocks were called as expected
env.OAuthStore.AssertExpectations(t)
env.SAService.AssertExpectations(t)
env.AcStore.AssertExpectations(t)
})
}
}

View File

@ -1,4 +1,4 @@
// Code generated by mockery v2.20.0. DO NOT EDIT.
// Code generated by mockery v2.35.2. DO NOT EDIT.
package oastest
@ -122,13 +122,26 @@ func (_m *MockStore) SaveExternalService(ctx context.Context, client *oauthserve
return r0
}
type mockConstructorTestingTNewMockStore interface {
mock.TestingT
Cleanup(func())
// UpdateExternalServiceGrantTypes provides a mock function with given fields: ctx, clientID, grantTypes
func (_m *MockStore) UpdateExternalServiceGrantTypes(ctx context.Context, clientID string, grantTypes string) error {
ret := _m.Called(ctx, clientID, grantTypes)
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok {
r0 = rf(ctx, clientID, grantTypes)
} else {
r0 = ret.Error(0)
}
return r0
}
// NewMockStore creates a new instance of MockStore. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMockStore(t mockConstructorTestingTNewMockStore) *MockStore {
// The first argument is typically a *testing.T value.
func NewMockStore(t interface {
mock.TestingT
Cleanup(func())
}) *MockStore {
mock := &MockStore{}
mock.Mock.Test(t)

View File

@ -11,7 +11,6 @@ import (
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/services/extsvcauth/oauthserver"
"github.com/grafana/grafana/pkg/services/extsvcauth/oauthserver/utils"
"github.com/grafana/grafana/pkg/util/errutil"
)
type store struct {
@ -101,13 +100,8 @@ func (s *store) SaveExternalService(ctx context.Context, client *oauthserver.OAu
}
return s.db.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
previous, errFetchExtSvc := getExternalServiceByName(sess, client.Name)
if errFetchExtSvc != nil {
var srcError errutil.Error
if errors.As(errFetchExtSvc, &srcError) {
if srcError.MessageID != oauthserver.ErrClientNotFoundMessageID {
return errFetchExtSvc
}
}
if errFetchExtSvc != nil && !errors.Is(errFetchExtSvc, oauthserver.ErrClientNotFound) {
return errFetchExtSvc
}
if previous == nil {
return registerExternalService(sess, client)
@ -132,7 +126,7 @@ func (s *store) GetExternalService(ctx context.Context, id string) (*oauthserver
return err
}
if !found {
return oauthserver.ErrClientNotFound(id)
return oauthserver.ErrClientNotFoundFn(id)
}
impersonatePermQuery := `SELECT action, scope FROM oauth_impersonate_permission WHERE client_id = ?`
@ -157,7 +151,7 @@ func (s *store) GetExternalServicePublicKey(ctx context.Context, clientID string
return err
}
if !found {
return oauthserver.ErrClientNotFound(clientID)
return oauthserver.ErrClientNotFoundFn(clientID)
}
return nil
}); err != nil {
@ -209,7 +203,7 @@ func getExternalServiceByName(sess *db.Session, name string) (*oauthserver.OAuth
return nil, err
}
if !found {
return nil, oauthserver.ErrClientNotFound(name)
return nil, oauthserver.ErrClientNotFoundFn(name)
}
impersonatePermQuery := `SELECT action, scope FROM oauth_impersonate_permission WHERE client_id = ?`
@ -217,3 +211,15 @@ func getExternalServiceByName(sess *db.Session, name string) (*oauthserver.OAuth
return res, errPerm
}
func (s *store) UpdateExternalServiceGrantTypes(ctx context.Context, clientID, grantTypes string) error {
if clientID == "" {
return oauthserver.ErrClientRequiredID
}
return s.db.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
query := `UPDATE oauth_client SET grant_types = ? WHERE client_id = ?`
_, err := sess.Exec(query, grantTypes, clientID)
return err
})
}

View File

@ -530,8 +530,7 @@ func TestLoader_Load_ExternalRegistration(t *testing.T) {
},
ExternalServiceRegistration: &plugindef.ExternalServiceRegistration{
Impersonation: &plugindef.Impersonation{
Enabled: boolPtr(true),
Groups: boolPtr(true),
Groups: boolPtr(true),
Permissions: []plugindef.Permission{
{
Action: "read",

View File

@ -41,11 +41,7 @@ func (s *Service) RegisterExternalService(ctx context.Context, svcName string, p
impersonation := extsvcauth.ImpersonationCfg{}
if svc.Impersonation != nil {
impersonation.Permissions = toAccessControlPermissions(svc.Impersonation.Permissions)
if svc.Impersonation.Enabled != nil {
impersonation.Enabled = *svc.Impersonation.Enabled
} else {
impersonation.Enabled = true
}
impersonation.Enabled = enabled
if svc.Impersonation.Groups != nil {
impersonation.Groups = *svc.Impersonation.Groups
} else {