diff --git a/pkg/api/common_test.go b/pkg/api/common_test.go index 264d084089b..0ff8083616a 100644 --- a/pkg/api/common_test.go +++ b/pkg/api/common_test.go @@ -21,12 +21,14 @@ import ( "github.com/grafana/grafana/pkg/infra/fs" "github.com/grafana/grafana/pkg/infra/remotecache" "github.com/grafana/grafana/pkg/infra/tracing" + "github.com/grafana/grafana/pkg/models/usertoken" "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol/acimpl" "github.com/grafana/grafana/pkg/services/annotations/annotationstest" "github.com/grafana/grafana/pkg/services/anonymous/anontest" "github.com/grafana/grafana/pkg/services/auth/authtest" "github.com/grafana/grafana/pkg/services/auth/jwt" + "github.com/grafana/grafana/pkg/services/authn" "github.com/grafana/grafana/pkg/services/authn/authntest" "github.com/grafana/grafana/pkg/services/contexthandler" "github.com/grafana/grafana/pkg/services/contexthandler/authproxy" @@ -177,6 +179,7 @@ type scenarioContext struct { authInfoService *logintest.AuthInfoServiceFake dashboardVersionService dashver.Service userService user.Service + ctxHdlr *contexthandler.ContextHandler } func (sc *scenarioContext) exec() { @@ -208,17 +211,20 @@ func getContextHandler(t *testing.T, cfg *setting.Cfg) *contexthandler.ContextHa ctxHdlr := contexthandler.ProvideService(cfg, userAuthTokenSvc, authJWTSvc, remoteCacheSvc, renderSvc, sqlStore, tracer, authProxy, loginService, nil, authenticator, usertest.NewUserServiceFake(), orgtest.NewOrgServiceFake(), - nil, featuremgmt.WithFeatures(), &authntest.FakeService{}, &anontest.FakeAnonymousSessionService{}) + nil, featuremgmt.WithFeatures(), &authntest.FakeService{ + ExpectedIdentity: &authn.Identity{OrgID: 1, ID: "user:1", SessionToken: &usertoken.UserToken{}}}, &anontest.FakeAnonymousSessionService{}) return ctxHdlr } func setupScenarioContext(t *testing.T, url string) *scenarioContext { cfg := setting.NewCfg() + ctxHdlr := getContextHandler(t, cfg) sc := &scenarioContext{ - url: url, - t: t, - cfg: cfg, + url: url, + t: t, + cfg: cfg, + ctxHdlr: ctxHdlr, } viewsPath, err := filepath.Abs("../../public/views") require.NoError(t, err) @@ -228,7 +234,7 @@ func setupScenarioContext(t *testing.T, url string) *scenarioContext { sc.m = web.New() sc.m.UseMiddleware(web.Renderer(viewsPath, "[[", "]]")) - sc.m.Use(getContextHandler(t, cfg).Middleware) + sc.m.Use(ctxHdlr.Middleware) return sc } diff --git a/pkg/api/index.go b/pkg/api/index.go index b87ba900854..e6988767327 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -17,6 +17,7 @@ import ( "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/login" + "github.com/grafana/grafana/pkg/services/org" pref "github.com/grafana/grafana/pkg/services/preference" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" @@ -80,6 +81,16 @@ func (hs *HTTPServer) setIndexViewData(c *contextmodel.ReqContext) (*dtos.IndexV theme := hs.getThemeForIndexData(prefs.Theme, c.Query("theme")) + userOrgCount := 1 + userOrgs, err := hs.orgService.GetUserOrgList(c.Req.Context(), &org.GetUserOrgListQuery{UserID: c.UserID}) + if err != nil { + hs.log.Error("Failed to count user orgs", "error", err) + } + + if len(userOrgs) > 0 { + userOrgCount = len(userOrgs) + } + hasAccess := ac.HasAccess(hs.AccessControl, c) hasEditPerm := hasAccess(ac.EvalAny(ac.EvalPermission(dashboards.ActionDashboardsCreate), ac.EvalPermission(dashboards.ActionFoldersCreate))) @@ -90,10 +101,10 @@ func (hs *HTTPServer) setIndexViewData(c *contextmodel.ReqContext) (*dtos.IndexV Login: c.Login, Email: c.Email, Name: c.Name, - OrgCount: c.OrgCount, OrgId: c.OrgID, OrgName: c.OrgName, OrgRole: c.OrgRole, + OrgCount: userOrgCount, GravatarUrl: dtos.GetGravatarUrl(c.Email), IsGrafanaAdmin: c.IsGrafanaAdmin, Theme: theme.ID, diff --git a/pkg/api/login_test.go b/pkg/api/login_test.go index c4c77d41db9..facdebd2554 100644 --- a/pkg/api/login_test.go +++ b/pkg/api/login_test.go @@ -595,18 +595,22 @@ func (r *loginHookTest) LoginHook(loginInfo *loginservice.LoginInfo, req *contex r.info = loginInfo } +// TOREMOVE: remove with context handler auth func TestLoginPostRunLokingHook(t *testing.T) { sc := setupScenarioContext(t, "/login") hookService := &hooks.HooksService{} hs := &HTTPServer{ log: log.New("test"), - Cfg: setting.NewCfg(), + Cfg: sc.cfg, License: &licensing.OSSLicensingService{}, AuthTokenService: authtest.NewFakeUserAuthTokenService(), Features: featuremgmt.WithFeatures(), HooksService: hookService, + authnService: sc.ctxHdlr.AuthnService, } + sc.cfg.AuthBrokerEnabled = false + sc.defaultHandler = routing.Wrap(func(c *contextmodel.ReqContext) response.Response { c.Req.Header.Set("Content-Type", "application/json") c.Req.Body = io.NopCloser(bytes.NewBufferString(`{"user":"admin","password":"admin"}`)) diff --git a/pkg/services/authn/authn.go b/pkg/services/authn/authn.go index e7bf6a66b65..d229dcd671f 100644 --- a/pkg/services/authn/authn.go +++ b/pkg/services/authn/authn.go @@ -180,8 +180,6 @@ const ( type Identity struct { // OrgID is the active organization for the entity. OrgID int64 - // OrgCount is the number of organizations the entity is a member of. - OrgCount int // OrgName is the name of the active organization. OrgName string // OrgRoles is the list of organizations the entity is a member of and their roles. @@ -271,7 +269,6 @@ func (i *Identity) SignedInUser() *user.SignedInUser { Name: i.Name, Email: i.Email, AuthenticatedBy: i.AuthenticatedBy, - OrgCount: i.OrgCount, IsGrafanaAdmin: isGrafanaAdmin, IsAnonymous: i.IsAnonymous, IsDisabled: i.IsDisabled, @@ -320,7 +317,6 @@ func IdentityFromSignedInUser(id string, usr *user.SignedInUser, params ClientPa Name: usr.Name, Email: usr.Email, AuthenticatedBy: authenticatedBy, - OrgCount: usr.OrgCount, IsGrafanaAdmin: &usr.IsGrafanaAdmin, IsDisabled: usr.IsDisabled, HelpFlags1: usr.HelpFlags1, diff --git a/pkg/services/authn/authnimpl/sync/user_sync.go b/pkg/services/authn/authnimpl/sync/user_sync.go index 9dfb46f4086..d72b391222b 100644 --- a/pkg/services/authn/authnimpl/sync/user_sync.go +++ b/pkg/services/authn/authnimpl/sync/user_sync.go @@ -387,7 +387,6 @@ func syncSignedInUserToIdentity(usr *user.SignedInUser, identity *authn.Identity identity.Email = usr.Email identity.OrgID = usr.OrgID identity.OrgName = usr.OrgName - identity.OrgCount = usr.OrgCount identity.OrgRoles = map[int64]org.RoleType{identity.OrgID: usr.OrgRole} identity.HelpFlags1 = usr.HelpFlags1 identity.Teams = usr.Teams diff --git a/pkg/services/authn/clients/api_key_test.go b/pkg/services/authn/clients/api_key_test.go index 56a7c081a1b..a996dcca3f7 100644 --- a/pkg/services/authn/clients/api_key_test.go +++ b/pkg/services/authn/clients/api_key_test.go @@ -76,14 +76,12 @@ func TestAPIKey_Authenticate(t *testing.T) { UserID: 1, OrgID: 1, IsServiceAccount: true, - OrgCount: 1, OrgRole: org.RoleViewer, Name: "test", }, expectedIdentity: &authn.Identity{ ID: "service-account:1", OrgID: 1, - OrgCount: 1, Name: "test", OrgRoles: map[int64]org.RoleType{1: org.RoleViewer}, IsGrafanaAdmin: boolPtr(false), diff --git a/pkg/services/authn/clients/ext_jwt_test.go b/pkg/services/authn/clients/ext_jwt_test.go index 205fb52c0dc..4e1ef8ce41a 100644 --- a/pkg/services/authn/clients/ext_jwt_test.go +++ b/pkg/services/authn/clients/ext_jwt_test.go @@ -151,7 +151,6 @@ func TestExtendedJWT_Authenticate(t *testing.T) { }, want: &authn.Identity{ OrgID: 1, - OrgCount: 0, OrgName: "", OrgRoles: map[int64]roletype.RoleType{1: roletype.RoleAdmin}, ID: "user:2", diff --git a/pkg/services/authn/clients/jwt_test.go b/pkg/services/authn/clients/jwt_test.go index 958113596ab..1ddb0da9de5 100644 --- a/pkg/services/authn/clients/jwt_test.go +++ b/pkg/services/authn/clients/jwt_test.go @@ -36,7 +36,6 @@ func TestAuthenticateJWT(t *testing.T) { jwtHeaderName := "X-Forwarded-User" wantID := &authn.Identity{ OrgID: 0, - OrgCount: 0, OrgName: "", OrgRoles: map[int64]roletype.RoleType{1: roletype.RoleAdmin}, ID: "", diff --git a/pkg/services/user/model.go b/pkg/services/user/model.go index cc4be041288..292a951b51c 100644 --- a/pkg/services/user/model.go +++ b/pkg/services/user/model.go @@ -211,7 +211,6 @@ type SignedInUser struct { AuthenticatedBy string ApiKeyID int64 `xorm:"api_key_id"` IsServiceAccount bool `xorm:"is_service_account"` - OrgCount int IsGrafanaAdmin bool IsAnonymous bool IsDisabled bool diff --git a/pkg/services/user/userimpl/store.go b/pkg/services/user/userimpl/store.go index cbd3b5a4ce4..51e99a91372 100644 --- a/pkg/services/user/userimpl/store.go +++ b/pkg/services/user/userimpl/store.go @@ -396,7 +396,6 @@ func (ss *sqlStore) GetSignedInUser(ctx context.Context, query *user.GetSignedIn u.is_disabled as is_disabled, u.help_flags1 as help_flags1, u.last_seen_at as last_seen_at, - (SELECT COUNT(*) FROM org_user where org_user.user_id = u.id) as org_count, org.name as org_name, org_user.role as org_role, org.id as org_id, diff --git a/pkg/tests/web/index_view_test.go b/pkg/tests/web/index_view_test.go index 041487886a6..0af4042dc03 100644 --- a/pkg/tests/web/index_view_test.go +++ b/pkg/tests/web/index_view_test.go @@ -117,56 +117,53 @@ func TestIntegrationIndexViewAnalytics(t *testing.T) { }, } - // can be removed once ff is removed - authBrokerStates := map[string]bool{"none": false, "authnService": true} - - for k, enabled := range authBrokerStates { - for _, tc := range testCases { - t.Run(tc.name+"-"+k, func(t *testing.T) { - grafDir, cfgPath := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{AuthBrokerEnabled: enabled}) - addr, store := testinfra.StartGrafana(t, grafDir, cfgPath) - createdUser := testinfra.CreateUser(t, store, user.CreateUserCommand{ - Login: "admin", - Password: "admin", - Email: "admin@grafana.com", - OrgID: 1, - }) + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + grafDir, cfgPath := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ + AuthBrokerEnabled: true, + }) + addr, store := testinfra.StartGrafana(t, grafDir, cfgPath) + createdUser := testinfra.CreateUser(t, store, user.CreateUserCommand{ + Login: "admin", + Password: "admin", + Email: "admin@grafana.com", + OrgID: 1, + }) - secretsService := secretsManager.SetupTestService(t, database.ProvideSecretsStore(store)) - authInfoStore := databaseAuthInfo.ProvideAuthInfoStore(store, secretsService, nil) + secretsService := secretsManager.SetupTestService(t, database.ProvideSecretsStore(store)) + authInfoStore := databaseAuthInfo.ProvideAuthInfoStore(store, secretsService, nil) - // insert user_auth relationship + // insert user_auth relationship + err := authInfoStore.SetAuthInfo(context.Background(), &login.SetAuthInfoCommand{ + AuthModule: tc.authModule, + AuthId: tc.setID, + UserId: createdUser.ID, + }) + require.NoError(t, err) + if tc.secondModule != "" { + // wait for the user_auth relationship to be inserted. TOFIX: this is a hack + time.Sleep(1 * time.Second) err := authInfoStore.SetAuthInfo(context.Background(), &login.SetAuthInfoCommand{ - AuthModule: tc.authModule, - AuthId: tc.setID, + AuthModule: tc.secondModule, + AuthId: tc.secondID, UserId: createdUser.ID, }) require.NoError(t, err) - if tc.secondModule != "" { - // wait for the user_auth relationship to be inserted. TOFIX: this is a hack - time.Sleep(1 * time.Second) - err := authInfoStore.SetAuthInfo(context.Background(), &login.SetAuthInfoCommand{ - AuthModule: tc.secondModule, - AuthId: tc.secondID, - UserId: createdUser.ID, - }) - require.NoError(t, err) - } - - // nolint:bodyclose - response, html := makeRequest(t, addr, "admin", "admin") - assert.Equal(t, http.StatusOK, response.StatusCode) - - // parse User.Analytics HTML view into user.AnalyticsSettings model - parsedHTML := strings.Split(html, "analytics\":")[1] - parsedHTML = strings.Split(parsedHTML, "},\n")[0] - - var analyticsSettings user.AnalyticsSettings - require.NoError(t, json.Unmarshal([]byte(parsedHTML), &analyticsSettings)) - - require.NotEmpty(t, analyticsSettings.IntercomIdentifier) - require.Equal(t, tc.wantIdentifier, analyticsSettings.Identifier) - }) - } + } + + // nolint:bodyclose + response, html := makeRequest(t, addr, "admin", "admin") + assert.Equal(t, http.StatusOK, response.StatusCode) + + // parse User.Analytics HTML view into user.AnalyticsSettings model + parsedHTML := strings.Split(html, "analytics\":")[1] + parsedHTML = strings.Split(parsedHTML, "},\n")[0] + + var analyticsSettings user.AnalyticsSettings + require.NoError(t, json.Unmarshal([]byte(parsedHTML), &analyticsSettings)) + + require.NotEmpty(t, analyticsSettings.IntercomIdentifier) + require.Equal(t, tc.wantIdentifier, analyticsSettings.Identifier) + }) } }