Files
grafana/pkg/services/oauthserver/oasimpl/token_test.go
Jo 44fa0697ce Auth: Signing Key persistence (#75487)
* signing key wip

use db keyset storage

add signing_key table

add testing for key storage

add ES256 key tests

Remove caching and implement UpdateOrCreate

Stabilize interfaces

* Encrypt private keys

* Fixup signer

* Fixup ext_jwt

* Add GetOrCreatePrivate with automatic key rotation

* use GetOrCreate for ext_jwt

* use GetOrCreate in id

* catch invalid block type

* fix broken test

* remove key generator

* reduce public interface of signing service
2023-10-04 10:37:27 +02:00

748 lines
24 KiB
Go

package oasimpl
import (
"context"
"crypto/rsa"
"encoding/json"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"
"time"
"github.com/google/uuid"
"github.com/ory/fosite"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"golang.org/x/crypto/bcrypt"
"golang.org/x/exp/maps"
"gopkg.in/square/go-jose.v2"
"gopkg.in/square/go-jose.v2/jwt"
"github.com/grafana/grafana/pkg/models/roletype"
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/oauthserver"
"github.com/grafana/grafana/pkg/services/serviceaccounts"
"github.com/grafana/grafana/pkg/services/team"
"github.com/grafana/grafana/pkg/services/user"
)
func TestOAuth2ServiceImpl_handleClientCredentials(t *testing.T) {
client1 := &oauthserver.ExternalService{
Name: "testapp",
ClientID: "RANDOMID",
GrantTypes: string(fosite.GrantTypeClientCredentials),
ServiceAccountID: 2,
SignedInUser: &user.SignedInUser{
UserID: 2,
Name: "Test App",
Login: "testapp",
OrgRole: roletype.RoleViewer,
Permissions: map[int64]map[string][]string{
oauthserver.TmpOrgID: {
"dashboards:read": {"dashboards:*", "folders:*"},
"dashboards:write": {"dashboards:uid:1"},
},
},
},
}
tests := []struct {
name string
scopes []string
client *oauthserver.ExternalService
expectedClaims map[string]any
wantErr bool
}{
{
name: "no claim without client_credentials grant type",
client: &oauthserver.ExternalService{
Name: "testapp",
ClientID: "RANDOMID",
GrantTypes: string(fosite.GrantTypeJWTBearer),
ServiceAccountID: 2,
SignedInUser: &user.SignedInUser{},
},
},
{
name: "no claims without scopes",
client: client1,
},
{
name: "profile claims",
client: client1,
scopes: []string{"profile"},
expectedClaims: map[string]any{"name": "Test App", "login": "testapp"},
},
{
name: "email claims should be empty",
client: client1,
scopes: []string{"email"},
},
{
name: "groups claims should be empty",
client: client1,
scopes: []string{"groups"},
},
{
name: "entitlements claims",
client: client1,
scopes: []string{"entitlements"},
expectedClaims: map[string]any{"entitlements": map[string][]string{
"dashboards:read": {"dashboards:*", "folders:*"},
"dashboards:write": {"dashboards:uid:1"},
}},
},
{
name: "scoped entitlements claims",
client: client1,
scopes: []string{"entitlements", "dashboards:write"},
expectedClaims: map[string]any{"entitlements": map[string][]string{
"dashboards:write": {"dashboards:uid:1"},
}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := context.Background()
env := setupTestEnv(t)
session := &fosite.DefaultSession{}
requester := fosite.NewAccessRequest(session)
requester.GrantTypes = fosite.Arguments(strings.Split(tt.client.GrantTypes, ","))
requester.RequestedScope = fosite.Arguments(tt.scopes)
sessionData := NewAuthSession()
err := env.S.handleClientCredentials(ctx, requester, sessionData, tt.client)
if tt.wantErr {
require.Error(t, err)
return
}
require.NoError(t, err)
if tt.expectedClaims == nil {
require.Empty(t, sessionData.JWTClaims.Extra)
return
}
require.Len(t, sessionData.JWTClaims.Extra, len(tt.expectedClaims))
for claimsKey, claimsValue := range tt.expectedClaims {
switch expected := claimsValue.(type) {
case []string:
require.ElementsMatch(t, claimsValue, sessionData.JWTClaims.Extra[claimsKey])
case map[string][]string:
actual, ok := sessionData.JWTClaims.Extra[claimsKey].(map[string][]string)
require.True(t, ok, "expected map[string][]string")
require.ElementsMatch(t, maps.Keys(expected), maps.Keys(actual))
for expKey, expValue := range expected {
require.ElementsMatch(t, expValue, actual[expKey])
}
default:
require.Equal(t, claimsValue, sessionData.JWTClaims.Extra[claimsKey])
}
}
})
}
}
func TestOAuth2ServiceImpl_handleJWTBearer(t *testing.T) {
now := time.Now()
client1 := &oauthserver.ExternalService{
Name: "testapp",
ClientID: "RANDOMID",
GrantTypes: string(fosite.GrantTypeJWTBearer),
ServiceAccountID: 2,
SignedInUser: &user.SignedInUser{
UserID: 2,
OrgID: oauthserver.TmpOrgID,
Name: "Test App",
Login: "testapp",
OrgRole: roletype.RoleViewer,
Permissions: map[int64]map[string][]string{
oauthserver.TmpOrgID: {
"users:impersonate": {"users:*"},
},
},
},
}
user56 := &user.User{
ID: 56,
Email: "user56@example.org",
Login: "user56",
Name: "User 56",
Updated: now,
}
teams := []*team.TeamDTO{
{ID: 1, Name: "Team 1", OrgID: 1},
{ID: 2, Name: "Team 2", OrgID: 1},
}
client1WithPerm := func(perms []ac.Permission) *oauthserver.ExternalService {
client := *client1
client.ImpersonatePermissions = perms
return &client
}
tests := []struct {
name string
initEnv func(*TestEnv)
scopes []string
client *oauthserver.ExternalService
subject string
expectedClaims map[string]any
wantErr bool
}{
{
name: "no claim without jwtbearer grant type",
client: &oauthserver.ExternalService{
Name: "testapp",
ClientID: "RANDOMID",
GrantTypes: string(fosite.GrantTypeClientCredentials),
ServiceAccountID: 2,
},
},
{
name: "err invalid subject",
client: client1,
subject: "invalid_subject",
wantErr: true,
},
{
name: "err client is not allowed to impersonate",
client: &oauthserver.ExternalService{
Name: "testapp",
ClientID: "RANDOMID",
GrantTypes: string(fosite.GrantTypeJWTBearer),
ServiceAccountID: 2,
SignedInUser: &user.SignedInUser{
UserID: 2,
Name: "Test App",
Login: "testapp",
OrgRole: roletype.RoleViewer,
Permissions: map[int64]map[string][]string{oauthserver.TmpOrgID: {}},
},
},
subject: "user:id:56",
wantErr: true,
},
{
name: "err subject not found",
initEnv: func(env *TestEnv) {
env.UserService.ExpectedError = user.ErrUserNotFound
},
client: client1,
subject: "user:id:56",
wantErr: true,
},
{
name: "no claim without scope",
initEnv: func(env *TestEnv) {
env.UserService.ExpectedUser = user56
},
client: client1,
subject: "user:id:56",
},
{
name: "profile claims",
initEnv: func(env *TestEnv) {
env.UserService.ExpectedUser = user56
},
client: client1,
subject: "user:id:56",
scopes: []string{"profile"},
expectedClaims: map[string]any{
"name": "User 56",
"login": "user56",
"updated_at": now.Unix(),
},
},
{
name: "email claim",
initEnv: func(env *TestEnv) {
env.UserService.ExpectedUser = user56
},
client: client1,
subject: "user:id:56",
scopes: []string{"email"},
expectedClaims: map[string]any{
"email": "user56@example.org",
},
},
{
name: "groups claim",
initEnv: func(env *TestEnv) {
env.UserService.ExpectedUser = user56
env.TeamService.ExpectedTeamsByUser = teams
},
client: client1,
subject: "user:id:56",
scopes: []string{"groups"},
expectedClaims: map[string]any{
"groups": []string{"Team 1", "Team 2"},
},
},
{
name: "no entitlement without permission intersection",
initEnv: func(env *TestEnv) {
env.UserService.ExpectedUser = user56
env.AcStore.On("GetUsersBasicRoles", mock.Anything, mock.Anything, mock.Anything).Return(map[int64][]string{
56: {"Viewer"}}, nil)
env.AcStore.On("SearchUsersPermissions", mock.Anything, mock.Anything, mock.Anything).Return(map[int64][]ac.Permission{
56: {{Action: "dashboards:read", Scope: "dashboards:uid:1"}},
}, nil)
},
client: client1WithPerm([]ac.Permission{
{Action: "datasources:read", Scope: "datasources:*"},
}),
subject: "user:id:56",
expectedClaims: map[string]any{
"entitlements": map[string][]string{},
},
scopes: []string{"entitlements"},
},
{
name: "entitlements contains only the intersection of permissions",
initEnv: func(env *TestEnv) {
env.UserService.ExpectedUser = user56
env.AcStore.On("GetUsersBasicRoles", mock.Anything, mock.Anything, mock.Anything).Return(map[int64][]string{
56: {"Viewer"}}, nil)
env.AcStore.On("SearchUsersPermissions", mock.Anything, mock.Anything, mock.Anything).Return(map[int64][]ac.Permission{
56: {
{Action: "dashboards:read", Scope: "dashboards:uid:1"},
{Action: "datasources:read", Scope: "datasources:uid:1"},
},
}, nil)
},
client: client1WithPerm([]ac.Permission{
{Action: "datasources:read", Scope: "datasources:*"},
}),
subject: "user:id:56",
expectedClaims: map[string]any{
"entitlements": map[string][]string{
"datasources:read": {"datasources:uid:1"},
},
},
scopes: []string{"entitlements"},
},
{
name: "entitlements have correctly translated users:self permissions",
initEnv: func(env *TestEnv) {
env.UserService.ExpectedUser = user56
env.AcStore.On("GetUsersBasicRoles", mock.Anything, mock.Anything, mock.Anything).Return(map[int64][]string{
56: {"Viewer"}}, nil)
env.AcStore.On("SearchUsersPermissions", mock.Anything, mock.Anything, mock.Anything).Return(map[int64][]ac.Permission{
56: {
{Action: "users:read", Scope: "global.users:id:*"},
{Action: "users.permissions:read", Scope: "users:id:*"},
}}, nil)
},
client: client1WithPerm([]ac.Permission{
{Action: "users:read", Scope: "global.users:self"},
{Action: "users.permissions:read", Scope: "users:self"},
}),
subject: "user:id:56",
expectedClaims: map[string]any{
"entitlements": map[string][]string{
"users:read": {"global.users:id:56"},
"users.permissions:read": {"users:id:56"},
},
},
scopes: []string{"entitlements"},
},
{
name: "entitlements have correctly translated teams:self permissions",
initEnv: func(env *TestEnv) {
env.UserService.ExpectedUser = user56
env.TeamService.ExpectedTeamsByUser = teams
env.AcStore.On("GetUsersBasicRoles", mock.Anything, mock.Anything, mock.Anything).Return(map[int64][]string{
56: {"Viewer"}}, nil)
env.AcStore.On("SearchUsersPermissions", mock.Anything, mock.Anything, mock.Anything).Return(map[int64][]ac.Permission{
56: {{Action: "teams:read", Scope: "teams:*"}}}, nil)
},
client: client1WithPerm([]ac.Permission{
{Action: "teams:read", Scope: "teams:self"},
}),
subject: "user:id:56",
expectedClaims: map[string]any{
"entitlements": map[string][]string{"teams:read": {"teams:id:1", "teams:id:2"}},
},
scopes: []string{"entitlements"},
},
{
name: "entitlements are correctly filtered based on scopes",
initEnv: func(env *TestEnv) {
env.UserService.ExpectedUser = user56
env.TeamService.ExpectedTeamsByUser = teams
env.AcStore.On("GetUsersBasicRoles", mock.Anything, mock.Anything, mock.Anything).Return(map[int64][]string{
56: {"Viewer"}}, nil)
env.AcStore.On("SearchUsersPermissions", mock.Anything, mock.Anything, mock.Anything).Return(map[int64][]ac.Permission{
56: {
{Action: "users:read", Scope: "global.users:id:*"},
{Action: "datasources:read", Scope: "datasources:uid:1"},
}}, nil)
},
client: client1WithPerm([]ac.Permission{
{Action: "users:read", Scope: "global.users:*"},
{Action: "datasources:read", Scope: "datasources:*"},
}),
subject: "user:id:56",
expectedClaims: map[string]any{
"entitlements": map[string][]string{"users:read": {"global.users:id:*"}},
},
scopes: []string{"entitlements", "users:read"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := context.Background()
env := setupTestEnv(t)
session := &fosite.DefaultSession{}
requester := fosite.NewAccessRequest(session)
requester.GrantTypes = fosite.Arguments(strings.Split(tt.client.GrantTypes, ","))
requester.RequestedScope = fosite.Arguments(tt.scopes)
requester.GrantedScope = fosite.Arguments(tt.scopes)
sessionData := NewAuthSession()
sessionData.Subject = tt.subject
if tt.initEnv != nil {
tt.initEnv(env)
}
err := env.S.handleJWTBearer(ctx, requester, sessionData, tt.client)
if tt.wantErr {
require.Error(t, err)
return
}
require.NoError(t, err)
if tt.expectedClaims == nil {
require.Empty(t, sessionData.JWTClaims.Extra)
return
}
require.Len(t, sessionData.JWTClaims.Extra, len(tt.expectedClaims))
for claimsKey, claimsValue := range tt.expectedClaims {
switch expected := claimsValue.(type) {
case []string:
require.ElementsMatch(t, claimsValue, sessionData.JWTClaims.Extra[claimsKey])
case map[string][]string:
actual, ok := sessionData.JWTClaims.Extra[claimsKey].(map[string][]string)
require.True(t, ok, "expected map[string][]string")
require.ElementsMatch(t, maps.Keys(expected), maps.Keys(actual))
for expKey, expValue := range expected {
require.ElementsMatch(t, expValue, actual[expKey])
}
default:
require.Equal(t, claimsValue, sessionData.JWTClaims.Extra[claimsKey])
}
}
env.AcStore.AssertExpectations(t)
})
}
}
type tokenResponse struct {
AccessToken string `json:"access_token"`
ExpiresIn int `json:"expires_in"`
Scope string `json:"scope"`
TokenType string `json:"token_type"`
}
type claims struct {
jwt.Claims
ClientID string `json:"client_id"`
Groups []string `json:"groups"`
Email string `json:"email"`
Name string `json:"name"`
Login string `json:"login"`
Scopes []string `json:"scope"`
Entitlements map[string][]string `json:"entitlements"`
}
func TestOAuth2ServiceImpl_HandleTokenRequest(t *testing.T) {
tests := []struct {
name string
tweakTestClient func(*oauthserver.ExternalService)
reqParams url.Values
wantCode int
wantScope []string
wantClaims *claims
}{
{
name: "should allow client credentials grant",
reqParams: url.Values{
"grant_type": {string(fosite.GrantTypeClientCredentials)},
"client_id": {"CLIENT1ID"},
"client_secret": {"CLIENT1SECRET"},
"scope": {"profile email groups entitlements"},
"audience": {AppURL},
},
wantCode: http.StatusOK,
wantScope: []string{"profile", "email", "groups", "entitlements"},
wantClaims: &claims{
Claims: jwt.Claims{
Subject: "user:id:2", // From client1.ServiceAccountID
Issuer: AppURL, // From env.S.Config.Issuer
Audience: jwt.Audience{AppURL},
},
ClientID: "CLIENT1ID",
Name: "client-1",
Login: "client-1",
Entitlements: map[string][]string{
"users:impersonate": {"users:*"},
},
},
},
{
name: "should allow jwt-bearer grant",
reqParams: url.Values{
"grant_type": {string(fosite.GrantTypeJWTBearer)},
"client_id": {"CLIENT1ID"},
"client_secret": {"CLIENT1SECRET"},
"assertion": {
genAssertion(t, Client1Key, "CLIENT1ID", "user:id:56", TokenURL, AppURL),
},
"scope": {"profile email groups entitlements"},
},
wantCode: http.StatusOK,
wantScope: []string{"profile", "email", "groups", "entitlements"},
wantClaims: &claims{
Claims: jwt.Claims{
Subject: "user:id:56", // To match the assertion
Issuer: AppURL, // From env.S.Config.Issuer
Audience: jwt.Audience{TokenURL, AppURL},
},
ClientID: "CLIENT1ID",
Email: "user56@example.org",
Name: "User 56",
Login: "user56",
Groups: []string{"Team 1", "Team 2"},
Entitlements: map[string][]string{
"dashboards:read": {"folders:uid:UID1"},
"folders:read": {"folders:uid:UID1"},
"users:read": {"global.users:id:56"},
},
},
},
{
name: "should deny jwt-bearer grant with wrong audience",
reqParams: url.Values{
"grant_type": {string(fosite.GrantTypeJWTBearer)},
"client_id": {"CLIENT1ID"},
"client_secret": {"CLIENT1SECRET"},
"assertion": {
genAssertion(t, Client1Key, "CLIENT1ID", "user:id:56", TokenURL, "invalid audience"),
},
"scope": {"profile email groups entitlements"},
},
wantCode: http.StatusForbidden,
},
{
name: "should deny jwt-bearer grant for clients without the grant",
reqParams: url.Values{
"grant_type": {string(fosite.GrantTypeJWTBearer)},
"client_id": {"CLIENT1ID"},
"client_secret": {"CLIENT1SECRET"},
"assertion": {
genAssertion(t, Client1Key, "CLIENT1ID", "user:id:56", TokenURL, AppURL),
},
"scope": {"profile email groups entitlements"},
},
tweakTestClient: func(es *oauthserver.ExternalService) {
es.GrantTypes = string(fosite.GrantTypeClientCredentials)
},
wantCode: http.StatusBadRequest,
},
{
name: "should deny client_credentials grant for clients without the grant",
reqParams: url.Values{
"grant_type": {string(fosite.GrantTypeClientCredentials)},
"client_id": {"CLIENT1ID"},
"client_secret": {"CLIENT1SECRET"},
"scope": {"profile email groups entitlements"},
"audience": {AppURL},
},
tweakTestClient: func(es *oauthserver.ExternalService) {
es.GrantTypes = string(fosite.GrantTypeJWTBearer)
},
wantCode: http.StatusBadRequest,
},
{
name: "should deny client_credentials grant with wrong secret",
reqParams: url.Values{
"grant_type": {string(fosite.GrantTypeClientCredentials)},
"client_id": {"CLIENT1ID"},
"client_secret": {"WRONG_SECRET"},
"scope": {"profile email groups entitlements"},
"audience": {AppURL},
},
tweakTestClient: func(es *oauthserver.ExternalService) {
es.GrantTypes = string(fosite.GrantTypeClientCredentials)
},
wantCode: http.StatusUnauthorized,
},
{
name: "should deny jwt-bearer grant with wrong secret",
reqParams: url.Values{
"grant_type": {string(fosite.GrantTypeJWTBearer)},
"client_id": {"CLIENT1ID"},
"client_secret": {"WRONG_SECRET"},
"assertion": {
genAssertion(t, Client1Key, "CLIENT1ID", "user:id:56", TokenURL, AppURL),
},
"scope": {"profile email groups entitlements"},
},
tweakTestClient: func(es *oauthserver.ExternalService) {
es.GrantTypes = string(fosite.GrantTypeJWTBearer)
},
wantCode: http.StatusUnauthorized,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
env := setupTestEnv(t)
setupHandleTokenRequestEnv(t, env, tt.tweakTestClient)
req := httptest.NewRequest("POST", "/oauth2/token", strings.NewReader(tt.reqParams.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
resp := httptest.NewRecorder()
env.S.HandleTokenRequest(resp, req)
require.Equal(t, tt.wantCode, resp.Code, resp.Body.String())
if tt.wantCode != http.StatusOK {
return
}
body := resp.Body.Bytes()
require.NotEmpty(t, body)
var tokenResp tokenResponse
require.NoError(t, json.Unmarshal(body, &tokenResp))
// Check token response
require.NotEmpty(t, tokenResp.Scope)
require.ElementsMatch(t, tt.wantScope, strings.Split(tokenResp.Scope, " "))
require.Positive(t, tokenResp.ExpiresIn)
require.Equal(t, "bearer", tokenResp.TokenType)
require.NotEmpty(t, tokenResp.AccessToken)
// Check access token
parsedToken, err := jwt.ParseSigned(tokenResp.AccessToken)
require.NoError(t, err)
require.Len(t, parsedToken.Headers, 1)
typeHeader := parsedToken.Headers[0].ExtraHeaders["typ"]
require.Equal(t, "at+jwt", strings.ToLower(typeHeader.(string)))
require.Equal(t, "RS256", parsedToken.Headers[0].Algorithm)
// Check access token claims
var claims claims
require.NoError(t, parsedToken.Claims(pk.Public(), &claims))
// Check times and remove them
require.Positive(t, claims.IssuedAt.Time())
require.Positive(t, claims.Expiry.Time())
claims.IssuedAt = jwt.NewNumericDate(time.Time{})
claims.Expiry = jwt.NewNumericDate(time.Time{})
// Check the ID and remove it
require.NotEmpty(t, claims.ID)
claims.ID = ""
// Compare the rest
require.Equal(t, tt.wantClaims, &claims)
})
}
}
func genAssertion(t *testing.T, signKey *rsa.PrivateKey, clientID, sub string, audience ...string) string {
key := jose.SigningKey{Algorithm: jose.RS256, Key: signKey}
assertion := jwt.Claims{
ID: uuid.New().String(),
Issuer: clientID,
Subject: sub,
Audience: audience,
Expiry: jwt.NewNumericDate(time.Now().Add(time.Hour)),
IssuedAt: jwt.NewNumericDate(time.Now()),
}
var signerOpts = jose.SignerOptions{}
signerOpts.WithType("JWT")
rsaSigner, errSigner := jose.NewSigner(key, &signerOpts)
require.NoError(t, errSigner)
builder := jwt.Signed(rsaSigner)
rawJWT, errSign := builder.Claims(assertion).CompactSerialize()
require.NoError(t, errSign)
return rawJWT
}
// setupHandleTokenRequestEnv creates a client and a user and sets all Mocks call for the handleTokenRequest test cases
func setupHandleTokenRequestEnv(t *testing.T, env *TestEnv, opt func(*oauthserver.ExternalService)) {
now := time.Now()
hashedSecret, err := bcrypt.GenerateFromPassword([]byte("CLIENT1SECRET"), bcrypt.DefaultCost)
require.NoError(t, err)
client1 := &oauthserver.ExternalService{
Name: "client-1",
ClientID: "CLIENT1ID",
Secret: string(hashedSecret),
GrantTypes: string(fosite.GrantTypeClientCredentials + "," + fosite.GrantTypeJWTBearer),
ServiceAccountID: 2,
ImpersonatePermissions: []ac.Permission{
{Action: "users:read", Scope: oauthserver.ScopeGlobalUsersSelf},
{Action: "users.permissions:read", Scope: oauthserver.ScopeUsersSelf},
{Action: "teams:read", Scope: oauthserver.ScopeTeamsSelf},
{Action: "folders:read", Scope: "folders:*"},
{Action: "dashboards:read", Scope: "folders:*"},
{Action: "dashboards:read", Scope: "dashboards:*"},
},
SelfPermissions: []ac.Permission{
{Action: "users:impersonate", Scope: "users:*"},
},
Audiences: AppURL,
}
// Apply any option the test case might need
if opt != nil {
opt(client1)
}
sa1 := &serviceaccounts.ServiceAccountProfileDTO{
Id: client1.ServiceAccountID,
Name: client1.Name,
Login: client1.Name,
OrgId: oauthserver.TmpOrgID,
IsDisabled: false,
Created: now,
Updated: now,
Role: "Viewer",
}
user56 := &user.User{
ID: 56,
Email: "user56@example.org",
Login: "user56",
Name: "User 56",
Updated: now,
}
user56Permissions := []ac.Permission{
{Action: "users:read", Scope: "global.users:id:56"},
{Action: "folders:read", Scope: "folders:uid:UID1"},
{Action: "dashboards:read", Scope: "folders:uid:UID1"},
{Action: "datasources:read", Scope: "datasources:uid:DS_UID2"}, // This one should be ignored when impersonating
}
user56Teams := []*team.TeamDTO{
{ID: 1, Name: "Team 1", OrgID: 1},
{ID: 2, Name: "Team 2", OrgID: 1},
}
// To retrieve the Client, its publicKey and its permissions
env.OAuthStore.On("GetExternalService", mock.Anything, client1.ClientID).Return(client1, nil)
env.OAuthStore.On("GetExternalServicePublicKey", mock.Anything, client1.ClientID).Return(&jose.JSONWebKey{Key: Client1Key.Public(), Algorithm: "RS256"}, nil)
env.SAService.On("RetrieveServiceAccount", mock.Anything, oauthserver.TmpOrgID, client1.ServiceAccountID).Return(sa1, nil)
env.AcStore.On("GetUserPermissions", mock.Anything, mock.Anything).Return(client1.SelfPermissions, nil)
// To retrieve the user to impersonate, its permissions and its teams
env.AcStore.On("SearchUsersPermissions", mock.Anything, mock.Anything, mock.Anything).Return(map[int64][]ac.Permission{
user56.ID: user56Permissions}, nil)
env.AcStore.On("GetUsersBasicRoles", mock.Anything, mock.Anything, mock.Anything).Return(map[int64][]string{
user56.ID: {"Viewer"}}, nil)
env.TeamService.ExpectedTeamsByUser = user56Teams
env.UserService.ExpectedUser = user56
}