Auth: remove org count from signedInUser (#72661)
* tweaks * remove org count from signedinUser * remove org count from signedinUser store * fix broken tests * restore frontend interface
This commit is contained in:
+11
-5
@@ -21,12 +21,14 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/infra/fs"
|
"github.com/grafana/grafana/pkg/infra/fs"
|
||||||
"github.com/grafana/grafana/pkg/infra/remotecache"
|
"github.com/grafana/grafana/pkg/infra/remotecache"
|
||||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
"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"
|
||||||
"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
|
"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
|
||||||
"github.com/grafana/grafana/pkg/services/annotations/annotationstest"
|
"github.com/grafana/grafana/pkg/services/annotations/annotationstest"
|
||||||
"github.com/grafana/grafana/pkg/services/anonymous/anontest"
|
"github.com/grafana/grafana/pkg/services/anonymous/anontest"
|
||||||
"github.com/grafana/grafana/pkg/services/auth/authtest"
|
"github.com/grafana/grafana/pkg/services/auth/authtest"
|
||||||
"github.com/grafana/grafana/pkg/services/auth/jwt"
|
"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/authn/authntest"
|
||||||
"github.com/grafana/grafana/pkg/services/contexthandler"
|
"github.com/grafana/grafana/pkg/services/contexthandler"
|
||||||
"github.com/grafana/grafana/pkg/services/contexthandler/authproxy"
|
"github.com/grafana/grafana/pkg/services/contexthandler/authproxy"
|
||||||
@@ -177,6 +179,7 @@ type scenarioContext struct {
|
|||||||
authInfoService *logintest.AuthInfoServiceFake
|
authInfoService *logintest.AuthInfoServiceFake
|
||||||
dashboardVersionService dashver.Service
|
dashboardVersionService dashver.Service
|
||||||
userService user.Service
|
userService user.Service
|
||||||
|
ctxHdlr *contexthandler.ContextHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sc *scenarioContext) exec() {
|
func (sc *scenarioContext) exec() {
|
||||||
@@ -208,17 +211,20 @@ func getContextHandler(t *testing.T, cfg *setting.Cfg) *contexthandler.ContextHa
|
|||||||
ctxHdlr := contexthandler.ProvideService(cfg, userAuthTokenSvc, authJWTSvc,
|
ctxHdlr := contexthandler.ProvideService(cfg, userAuthTokenSvc, authJWTSvc,
|
||||||
remoteCacheSvc, renderSvc, sqlStore, tracer, authProxy, loginService, nil,
|
remoteCacheSvc, renderSvc, sqlStore, tracer, authProxy, loginService, nil,
|
||||||
authenticator, usertest.NewUserServiceFake(), orgtest.NewOrgServiceFake(),
|
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
|
return ctxHdlr
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupScenarioContext(t *testing.T, url string) *scenarioContext {
|
func setupScenarioContext(t *testing.T, url string) *scenarioContext {
|
||||||
cfg := setting.NewCfg()
|
cfg := setting.NewCfg()
|
||||||
|
ctxHdlr := getContextHandler(t, cfg)
|
||||||
sc := &scenarioContext{
|
sc := &scenarioContext{
|
||||||
url: url,
|
url: url,
|
||||||
t: t,
|
t: t,
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
|
ctxHdlr: ctxHdlr,
|
||||||
}
|
}
|
||||||
viewsPath, err := filepath.Abs("../../public/views")
|
viewsPath, err := filepath.Abs("../../public/views")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -228,7 +234,7 @@ func setupScenarioContext(t *testing.T, url string) *scenarioContext {
|
|||||||
|
|
||||||
sc.m = web.New()
|
sc.m = web.New()
|
||||||
sc.m.UseMiddleware(web.Renderer(viewsPath, "[[", "]]"))
|
sc.m.UseMiddleware(web.Renderer(viewsPath, "[[", "]]"))
|
||||||
sc.m.Use(getContextHandler(t, cfg).Middleware)
|
sc.m.Use(ctxHdlr.Middleware)
|
||||||
|
|
||||||
return sc
|
return sc
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-1
@@ -17,6 +17,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/login"
|
"github.com/grafana/grafana/pkg/services/login"
|
||||||
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
pref "github.com/grafana/grafana/pkg/services/preference"
|
pref "github.com/grafana/grafana/pkg/services/preference"
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"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"))
|
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)
|
hasAccess := ac.HasAccess(hs.AccessControl, c)
|
||||||
hasEditPerm := hasAccess(ac.EvalAny(ac.EvalPermission(dashboards.ActionDashboardsCreate), ac.EvalPermission(dashboards.ActionFoldersCreate)))
|
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,
|
Login: c.Login,
|
||||||
Email: c.Email,
|
Email: c.Email,
|
||||||
Name: c.Name,
|
Name: c.Name,
|
||||||
OrgCount: c.OrgCount,
|
|
||||||
OrgId: c.OrgID,
|
OrgId: c.OrgID,
|
||||||
OrgName: c.OrgName,
|
OrgName: c.OrgName,
|
||||||
OrgRole: c.OrgRole,
|
OrgRole: c.OrgRole,
|
||||||
|
OrgCount: userOrgCount,
|
||||||
GravatarUrl: dtos.GetGravatarUrl(c.Email),
|
GravatarUrl: dtos.GetGravatarUrl(c.Email),
|
||||||
IsGrafanaAdmin: c.IsGrafanaAdmin,
|
IsGrafanaAdmin: c.IsGrafanaAdmin,
|
||||||
Theme: theme.ID,
|
Theme: theme.ID,
|
||||||
|
|||||||
@@ -595,18 +595,22 @@ func (r *loginHookTest) LoginHook(loginInfo *loginservice.LoginInfo, req *contex
|
|||||||
r.info = loginInfo
|
r.info = loginInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TOREMOVE: remove with context handler auth
|
||||||
func TestLoginPostRunLokingHook(t *testing.T) {
|
func TestLoginPostRunLokingHook(t *testing.T) {
|
||||||
sc := setupScenarioContext(t, "/login")
|
sc := setupScenarioContext(t, "/login")
|
||||||
hookService := &hooks.HooksService{}
|
hookService := &hooks.HooksService{}
|
||||||
hs := &HTTPServer{
|
hs := &HTTPServer{
|
||||||
log: log.New("test"),
|
log: log.New("test"),
|
||||||
Cfg: setting.NewCfg(),
|
Cfg: sc.cfg,
|
||||||
License: &licensing.OSSLicensingService{},
|
License: &licensing.OSSLicensingService{},
|
||||||
AuthTokenService: authtest.NewFakeUserAuthTokenService(),
|
AuthTokenService: authtest.NewFakeUserAuthTokenService(),
|
||||||
Features: featuremgmt.WithFeatures(),
|
Features: featuremgmt.WithFeatures(),
|
||||||
HooksService: hookService,
|
HooksService: hookService,
|
||||||
|
authnService: sc.ctxHdlr.AuthnService,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sc.cfg.AuthBrokerEnabled = false
|
||||||
|
|
||||||
sc.defaultHandler = routing.Wrap(func(c *contextmodel.ReqContext) response.Response {
|
sc.defaultHandler = routing.Wrap(func(c *contextmodel.ReqContext) response.Response {
|
||||||
c.Req.Header.Set("Content-Type", "application/json")
|
c.Req.Header.Set("Content-Type", "application/json")
|
||||||
c.Req.Body = io.NopCloser(bytes.NewBufferString(`{"user":"admin","password":"admin"}`))
|
c.Req.Body = io.NopCloser(bytes.NewBufferString(`{"user":"admin","password":"admin"}`))
|
||||||
|
|||||||
@@ -180,8 +180,6 @@ const (
|
|||||||
type Identity struct {
|
type Identity struct {
|
||||||
// OrgID is the active organization for the entity.
|
// OrgID is the active organization for the entity.
|
||||||
OrgID int64
|
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 is the name of the active organization.
|
||||||
OrgName string
|
OrgName string
|
||||||
// OrgRoles is the list of organizations the entity is a member of and their roles.
|
// 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,
|
Name: i.Name,
|
||||||
Email: i.Email,
|
Email: i.Email,
|
||||||
AuthenticatedBy: i.AuthenticatedBy,
|
AuthenticatedBy: i.AuthenticatedBy,
|
||||||
OrgCount: i.OrgCount,
|
|
||||||
IsGrafanaAdmin: isGrafanaAdmin,
|
IsGrafanaAdmin: isGrafanaAdmin,
|
||||||
IsAnonymous: i.IsAnonymous,
|
IsAnonymous: i.IsAnonymous,
|
||||||
IsDisabled: i.IsDisabled,
|
IsDisabled: i.IsDisabled,
|
||||||
@@ -320,7 +317,6 @@ func IdentityFromSignedInUser(id string, usr *user.SignedInUser, params ClientPa
|
|||||||
Name: usr.Name,
|
Name: usr.Name,
|
||||||
Email: usr.Email,
|
Email: usr.Email,
|
||||||
AuthenticatedBy: authenticatedBy,
|
AuthenticatedBy: authenticatedBy,
|
||||||
OrgCount: usr.OrgCount,
|
|
||||||
IsGrafanaAdmin: &usr.IsGrafanaAdmin,
|
IsGrafanaAdmin: &usr.IsGrafanaAdmin,
|
||||||
IsDisabled: usr.IsDisabled,
|
IsDisabled: usr.IsDisabled,
|
||||||
HelpFlags1: usr.HelpFlags1,
|
HelpFlags1: usr.HelpFlags1,
|
||||||
|
|||||||
@@ -387,7 +387,6 @@ func syncSignedInUserToIdentity(usr *user.SignedInUser, identity *authn.Identity
|
|||||||
identity.Email = usr.Email
|
identity.Email = usr.Email
|
||||||
identity.OrgID = usr.OrgID
|
identity.OrgID = usr.OrgID
|
||||||
identity.OrgName = usr.OrgName
|
identity.OrgName = usr.OrgName
|
||||||
identity.OrgCount = usr.OrgCount
|
|
||||||
identity.OrgRoles = map[int64]org.RoleType{identity.OrgID: usr.OrgRole}
|
identity.OrgRoles = map[int64]org.RoleType{identity.OrgID: usr.OrgRole}
|
||||||
identity.HelpFlags1 = usr.HelpFlags1
|
identity.HelpFlags1 = usr.HelpFlags1
|
||||||
identity.Teams = usr.Teams
|
identity.Teams = usr.Teams
|
||||||
|
|||||||
@@ -76,14 +76,12 @@ func TestAPIKey_Authenticate(t *testing.T) {
|
|||||||
UserID: 1,
|
UserID: 1,
|
||||||
OrgID: 1,
|
OrgID: 1,
|
||||||
IsServiceAccount: true,
|
IsServiceAccount: true,
|
||||||
OrgCount: 1,
|
|
||||||
OrgRole: org.RoleViewer,
|
OrgRole: org.RoleViewer,
|
||||||
Name: "test",
|
Name: "test",
|
||||||
},
|
},
|
||||||
expectedIdentity: &authn.Identity{
|
expectedIdentity: &authn.Identity{
|
||||||
ID: "service-account:1",
|
ID: "service-account:1",
|
||||||
OrgID: 1,
|
OrgID: 1,
|
||||||
OrgCount: 1,
|
|
||||||
Name: "test",
|
Name: "test",
|
||||||
OrgRoles: map[int64]org.RoleType{1: org.RoleViewer},
|
OrgRoles: map[int64]org.RoleType{1: org.RoleViewer},
|
||||||
IsGrafanaAdmin: boolPtr(false),
|
IsGrafanaAdmin: boolPtr(false),
|
||||||
|
|||||||
@@ -151,7 +151,6 @@ func TestExtendedJWT_Authenticate(t *testing.T) {
|
|||||||
},
|
},
|
||||||
want: &authn.Identity{
|
want: &authn.Identity{
|
||||||
OrgID: 1,
|
OrgID: 1,
|
||||||
OrgCount: 0,
|
|
||||||
OrgName: "",
|
OrgName: "",
|
||||||
OrgRoles: map[int64]roletype.RoleType{1: roletype.RoleAdmin},
|
OrgRoles: map[int64]roletype.RoleType{1: roletype.RoleAdmin},
|
||||||
ID: "user:2",
|
ID: "user:2",
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ func TestAuthenticateJWT(t *testing.T) {
|
|||||||
jwtHeaderName := "X-Forwarded-User"
|
jwtHeaderName := "X-Forwarded-User"
|
||||||
wantID := &authn.Identity{
|
wantID := &authn.Identity{
|
||||||
OrgID: 0,
|
OrgID: 0,
|
||||||
OrgCount: 0,
|
|
||||||
OrgName: "",
|
OrgName: "",
|
||||||
OrgRoles: map[int64]roletype.RoleType{1: roletype.RoleAdmin},
|
OrgRoles: map[int64]roletype.RoleType{1: roletype.RoleAdmin},
|
||||||
ID: "",
|
ID: "",
|
||||||
|
|||||||
@@ -211,7 +211,6 @@ type SignedInUser struct {
|
|||||||
AuthenticatedBy string
|
AuthenticatedBy string
|
||||||
ApiKeyID int64 `xorm:"api_key_id"`
|
ApiKeyID int64 `xorm:"api_key_id"`
|
||||||
IsServiceAccount bool `xorm:"is_service_account"`
|
IsServiceAccount bool `xorm:"is_service_account"`
|
||||||
OrgCount int
|
|
||||||
IsGrafanaAdmin bool
|
IsGrafanaAdmin bool
|
||||||
IsAnonymous bool
|
IsAnonymous bool
|
||||||
IsDisabled bool
|
IsDisabled bool
|
||||||
|
|||||||
@@ -396,7 +396,6 @@ func (ss *sqlStore) GetSignedInUser(ctx context.Context, query *user.GetSignedIn
|
|||||||
u.is_disabled as is_disabled,
|
u.is_disabled as is_disabled,
|
||||||
u.help_flags1 as help_flags1,
|
u.help_flags1 as help_flags1,
|
||||||
u.last_seen_at as last_seen_at,
|
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.name as org_name,
|
||||||
org_user.role as org_role,
|
org_user.role as org_role,
|
||||||
org.id as org_id,
|
org.id as org_id,
|
||||||
|
|||||||
@@ -117,56 +117,53 @@ func TestIntegrationIndexViewAnalytics(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// can be removed once ff is removed
|
for _, tc := range testCases {
|
||||||
authBrokerStates := map[string]bool{"none": false, "authnService": true}
|
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,
|
||||||
|
})
|
||||||
|
|
||||||
for k, enabled := range authBrokerStates {
|
secretsService := secretsManager.SetupTestService(t, database.ProvideSecretsStore(store))
|
||||||
for _, tc := range testCases {
|
authInfoStore := databaseAuthInfo.ProvideAuthInfoStore(store, secretsService, nil)
|
||||||
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,
|
|
||||||
})
|
|
||||||
|
|
||||||
secretsService := secretsManager.SetupTestService(t, database.ProvideSecretsStore(store))
|
// insert user_auth relationship
|
||||||
authInfoStore := databaseAuthInfo.ProvideAuthInfoStore(store, secretsService, nil)
|
err := authInfoStore.SetAuthInfo(context.Background(), &login.SetAuthInfoCommand{
|
||||||
|
AuthModule: tc.authModule,
|
||||||
// insert user_auth relationship
|
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{
|
err := authInfoStore.SetAuthInfo(context.Background(), &login.SetAuthInfoCommand{
|
||||||
AuthModule: tc.authModule,
|
AuthModule: tc.secondModule,
|
||||||
AuthId: tc.setID,
|
AuthId: tc.secondID,
|
||||||
UserId: createdUser.ID,
|
UserId: createdUser.ID,
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
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
|
// nolint:bodyclose
|
||||||
response, html := makeRequest(t, addr, "admin", "admin")
|
response, html := makeRequest(t, addr, "admin", "admin")
|
||||||
assert.Equal(t, http.StatusOK, response.StatusCode)
|
assert.Equal(t, http.StatusOK, response.StatusCode)
|
||||||
|
|
||||||
// parse User.Analytics HTML view into user.AnalyticsSettings model
|
// parse User.Analytics HTML view into user.AnalyticsSettings model
|
||||||
parsedHTML := strings.Split(html, "analytics\":")[1]
|
parsedHTML := strings.Split(html, "analytics\":")[1]
|
||||||
parsedHTML = strings.Split(parsedHTML, "},\n")[0]
|
parsedHTML = strings.Split(parsedHTML, "},\n")[0]
|
||||||
|
|
||||||
var analyticsSettings user.AnalyticsSettings
|
var analyticsSettings user.AnalyticsSettings
|
||||||
require.NoError(t, json.Unmarshal([]byte(parsedHTML), &analyticsSettings))
|
require.NoError(t, json.Unmarshal([]byte(parsedHTML), &analyticsSettings))
|
||||||
|
|
||||||
require.NotEmpty(t, analyticsSettings.IntercomIdentifier)
|
require.NotEmpty(t, analyticsSettings.IntercomIdentifier)
|
||||||
require.Equal(t, tc.wantIdentifier, analyticsSettings.Identifier)
|
require.Equal(t, tc.wantIdentifier, analyticsSettings.Identifier)
|
||||||
})
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user