The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/pkg/services/extsvcauth/oauthserver/oasimpl/token_test.go

747 lines
24 KiB

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/extsvcauth/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.OAuthExternalService{
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.OAuthExternalService
expectedClaims map[string]any
wantErr bool
}{
{
name: "no claim without client_credentials grant type",
client: &oauthserver.OAuthExternalService{
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.OAuthExternalService{
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.OAuthExternalService {
client := *client1
client.ImpersonatePermissions = perms
return &client
}
tests := []struct {
name string
initEnv func(*TestEnv)
scopes []string
client *oauthserver.OAuthExternalService
subject string
expectedClaims map[string]any
wantErr bool
}{
{
name: "no claim without jwtbearer grant type",
client: &oauthserver.OAuthExternalService{
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.OAuthExternalService{
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.OAuthExternalService)
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.OAuthExternalService) {
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.OAuthExternalService) {
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.OAuthExternalService) {
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.OAuthExternalService) {
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.OAuthExternalService)) {
now := time.Now()
hashedSecret, err := bcrypt.GenerateFromPassword([]byte("CLIENT1SECRET"), bcrypt.DefaultCost)
require.NoError(t, err)
client1 := &oauthserver.OAuthExternalService{
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
}