RBAC: Remove legacy ac from authorization middleware (#68898)

remove legacy AC fallback from RBAC middleware, and some unused auth logic
This commit is contained in:
Ieva
2023-05-24 09:49:42 +01:00
committed by GitHub
parent 323cbe1997
commit 4980b64274
21 changed files with 214 additions and 437 deletions
+2 -4
View File
@@ -38,10 +38,8 @@ func (api *AccessControlAPI) RegisterAPIEndpoints() {
rr.Get("/user/permissions", middleware.ReqSignedIn, routing.Wrap(api.getUserPermissions))
if api.features.IsEnabled(featuremgmt.FlagAccessControlOnCall) {
userIDScope := ac.Scope("users", "id", ac.Parameter(":userID"))
rr.Get("/users/permissions/search", authorize(middleware.ReqSignedIn,
ac.EvalPermission(ac.ActionUsersPermissionsRead)), routing.Wrap(api.searchUsersPermissions))
rr.Get("/user/:userID/permissions/search", authorize(middleware.ReqSignedIn,
ac.EvalPermission(ac.ActionUsersPermissionsRead, userIDScope)), routing.Wrap(api.searchUserPermissions))
rr.Get("/users/permissions/search", authorize(ac.EvalPermission(ac.ActionUsersPermissionsRead)), routing.Wrap(api.searchUsersPermissions))
rr.Get("/user/:userID/permissions/search", authorize(ac.EvalPermission(ac.ActionUsersPermissionsRead, userIDScope)), routing.Wrap(api.searchUserPermissions))
}
})
}
+4 -12
View File
@@ -24,12 +24,8 @@ import (
"github.com/grafana/grafana/pkg/web"
)
func Middleware(ac AccessControl) func(web.Handler, Evaluator) web.Handler {
return func(fallback web.Handler, evaluator Evaluator) web.Handler {
if ac.IsDisabled() {
return fallback
}
func Middleware(ac AccessControl) func(Evaluator) web.Handler {
return func(evaluator Evaluator) web.Handler {
return func(c *contextmodel.ReqContext) {
if c.AllowAnonymous {
forceLogin, _ := strconv.ParseBool(c.Req.URL.Query().Get("forceLogin")) // ignoring error, assuming false for non-true values is ok.
@@ -180,12 +176,8 @@ type userCache interface {
GetSignedInUserWithCacheCtx(ctx context.Context, query *user.GetSignedInUserQuery) (*user.SignedInUser, error)
}
func AuthorizeInOrgMiddleware(ac AccessControl, service Service, cache userCache) func(web.Handler, OrgIDGetter, Evaluator) web.Handler {
return func(fallback web.Handler, getTargetOrg OrgIDGetter, evaluator Evaluator) web.Handler {
if ac.IsDisabled() {
return fallback
}
func AuthorizeInOrgMiddleware(ac AccessControl, service Service, cache userCache) func(OrgIDGetter, Evaluator) web.Handler {
return func(getTargetOrg OrgIDGetter, evaluator Evaluator) web.Handler {
return func(c *contextmodel.ReqContext) {
// using a copy of the user not to modify the signedInUser, yet perform the permission evaluation in another org
userCopy := *(c.SignedInUser)
+2 -17
View File
@@ -18,7 +18,6 @@ import (
type middlewareTestCase struct {
desc string
expectFallback bool
expectEndpoint bool
evaluator accesscontrol.Evaluator
ac accesscontrol.AccessControl
@@ -26,19 +25,12 @@ type middlewareTestCase struct {
func TestMiddleware(t *testing.T) {
tests := []middlewareTestCase{
{
desc: "should use fallback if access control is disabled",
ac: mock.New().WithDisabled(),
expectFallback: true,
expectEndpoint: true,
},
{
desc: "should pass middleware for correct permissions",
ac: mock.New().WithPermissions(
[]accesscontrol.Permission{{Action: "users:read", Scope: "users:*"}},
),
evaluator: accesscontrol.EvalPermission("users:read", "users:*"),
expectFallback: false,
expectEndpoint: true,
},
{
@@ -47,23 +39,17 @@ func TestMiddleware(t *testing.T) {
[]accesscontrol.Permission{{Action: "users:read", Scope: "users:1"}},
),
evaluator: accesscontrol.EvalPermission("users:read", "users:*"),
expectFallback: false,
expectEndpoint: false,
},
}
for _, test := range tests {
t.Run(test.desc, func(t *testing.T) {
fallbackCalled := false
fallback := func(c *contextmodel.ReqContext) {
fallbackCalled = true
}
server := web.New()
server.UseMiddleware(web.Renderer("../../public/views", "[[", "]]"))
server.Use(contextProvider())
server.Use(accesscontrol.Middleware(test.ac)(fallback, test.evaluator))
server.Use(accesscontrol.Middleware(test.ac)(test.evaluator))
endpointCalled := false
server.Get("/", func(c *contextmodel.ReqContext) {
@@ -77,7 +63,6 @@ func TestMiddleware(t *testing.T) {
server.ServeHTTP(recorder, request)
assert.Equal(t, test.expectFallback, fallbackCalled)
assert.Equal(t, test.expectEndpoint, endpointCalled)
})
}
@@ -111,7 +96,7 @@ func TestMiddleware_forceLogin(t *testing.T) {
c.IsSignedIn = false
}))
server.Use(
accesscontrol.Middleware(ac)(nil, accesscontrol.EvalPermission("endpoint:read", "endpoint:1")),
accesscontrol.Middleware(ac)(accesscontrol.EvalPermission("endpoint:read", "endpoint:1")),
)
request, err := http.NewRequest(http.MethodGet, tc.url, nil)
@@ -32,7 +32,6 @@ func newApi(ac accesscontrol.AccessControl, router routing.RouteRegister, manage
func (a *api) registerEndpoints() {
auth := accesscontrol.Middleware(a.ac)
disable := disableMiddleware(a.ac.IsDisabled())
licenseMW := a.service.options.LicenseMW
if licenseMW == nil {
licenseMW = nopMiddleware
@@ -42,17 +41,17 @@ func (a *api) registerEndpoints() {
actionRead := fmt.Sprintf("%s.permissions:read", a.service.options.Resource)
actionWrite := fmt.Sprintf("%s.permissions:write", a.service.options.Resource)
scope := accesscontrol.Scope(a.service.options.Resource, a.service.options.ResourceAttribute, accesscontrol.Parameter(":resourceID"))
r.Get("/description", auth(disable, accesscontrol.EvalPermission(actionRead)), routing.Wrap(a.getDescription))
r.Get("/:resourceID", auth(disable, accesscontrol.EvalPermission(actionRead, scope)), routing.Wrap(a.getPermissions))
r.Post("/:resourceID", licenseMW, auth(disable, accesscontrol.EvalPermission(actionWrite, scope)), routing.Wrap(a.setPermissions))
r.Get("/description", auth(accesscontrol.EvalPermission(actionRead)), routing.Wrap(a.getDescription))
r.Get("/:resourceID", auth(accesscontrol.EvalPermission(actionRead, scope)), routing.Wrap(a.getPermissions))
r.Post("/:resourceID", licenseMW, auth(accesscontrol.EvalPermission(actionWrite, scope)), routing.Wrap(a.setPermissions))
if a.service.options.Assignments.Users {
r.Post("/:resourceID/users/:userID", licenseMW, auth(disable, accesscontrol.EvalPermission(actionWrite, scope)), routing.Wrap(a.setUserPermission))
r.Post("/:resourceID/users/:userID", licenseMW, auth(accesscontrol.EvalPermission(actionWrite, scope)), routing.Wrap(a.setUserPermission))
}
if a.service.options.Assignments.Teams {
r.Post("/:resourceID/teams/:teamID", licenseMW, auth(disable, accesscontrol.EvalPermission(actionWrite, scope)), routing.Wrap(a.setTeamPermission))
r.Post("/:resourceID/teams/:teamID", licenseMW, auth(accesscontrol.EvalPermission(actionWrite, scope)), routing.Wrap(a.setTeamPermission))
}
if a.service.options.Assignments.BuiltInRoles {
r.Post("/:resourceID/builtInRoles/:builtInRole", licenseMW, auth(disable, accesscontrol.EvalPermission(actionWrite, scope)), routing.Wrap(a.setBuiltinRolePermission))
r.Post("/:resourceID/builtInRoles/:builtInRole", licenseMW, auth(accesscontrol.EvalPermission(actionWrite, scope)), routing.Wrap(a.setBuiltinRolePermission))
}
})
}
@@ -1,19 +1,7 @@
package resourcepermissions
import (
"net/http"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
"github.com/grafana/grafana/pkg/web"
)
func disableMiddleware(shouldDisable bool) web.Handler {
return func(c *contextmodel.ReqContext) {
if shouldDisable {
c.Resp.WriteHeader(http.StatusNotFound)
return
}
}
}
func nopMiddleware(c *contextmodel.ReqContext) {}
+6 -6
View File
@@ -17,16 +17,16 @@ func (s *CorrelationsService) registerAPIEndpoints() {
uidScope := datasources.ScopeProvider.GetResourceScopeUID(ac.Parameter(":uid"))
authorize := ac.Middleware(s.AccessControl)
s.RouteRegister.Get("/api/datasources/correlations", middleware.ReqSignedIn, authorize(middleware.ReqSignedIn, ac.EvalPermission(datasources.ActionRead)), routing.Wrap(s.getCorrelationsHandler))
s.RouteRegister.Get("/api/datasources/correlations", middleware.ReqSignedIn, authorize(ac.EvalPermission(datasources.ActionRead)), routing.Wrap(s.getCorrelationsHandler))
s.RouteRegister.Group("/api/datasources/uid/:uid/correlations", func(entities routing.RouteRegister) {
entities.Get("/", authorize(middleware.ReqSignedIn, ac.EvalPermission(datasources.ActionRead)), routing.Wrap(s.getCorrelationsBySourceUIDHandler))
entities.Post("/", authorize(middleware.ReqOrgAdmin, ac.EvalPermission(datasources.ActionWrite, uidScope)), routing.Wrap(s.createHandler))
entities.Get("/", authorize(ac.EvalPermission(datasources.ActionRead)), routing.Wrap(s.getCorrelationsBySourceUIDHandler))
entities.Post("/", authorize(ac.EvalPermission(datasources.ActionWrite, uidScope)), routing.Wrap(s.createHandler))
entities.Group("/:correlationUID", func(entities routing.RouteRegister) {
entities.Get("/", authorize(middleware.ReqSignedIn, ac.EvalPermission(datasources.ActionRead)), routing.Wrap(s.getCorrelationHandler))
entities.Delete("/", authorize(middleware.ReqOrgAdmin, ac.EvalPermission(datasources.ActionWrite, uidScope)), routing.Wrap(s.deleteHandler))
entities.Patch("/", authorize(middleware.ReqOrgAdmin, ac.EvalPermission(datasources.ActionWrite, uidScope)), routing.Wrap(s.updateHandler))
entities.Get("/", authorize(ac.EvalPermission(datasources.ActionRead)), routing.Wrap(s.getCorrelationHandler))
entities.Delete("/", authorize(ac.EvalPermission(datasources.ActionWrite, uidScope)), routing.Wrap(s.deleteHandler))
entities.Patch("/", authorize(ac.EvalPermission(datasources.ActionWrite, uidScope)), routing.Wrap(s.updateHandler))
})
}, middleware.ReqSignedIn)
}
+1 -1
View File
@@ -38,7 +38,7 @@ func (api *ImportDashboardAPI) RegisterAPIEndpoints(routeRegister routing.RouteR
routeRegister.Group("/api/dashboards", func(route routing.RouteRegister) {
route.Post(
"/import",
authorize(middleware.ReqSignedIn, accesscontrol.EvalPermission(dashboards.ActionDashboardsCreate)),
authorize(accesscontrol.EvalPermission(dashboards.ActionDashboardsCreate)),
routing.Wrap(api.ImportDashboard),
)
}, middleware.ReqSignedIn)
+4 -5
View File
@@ -56,13 +56,12 @@ func ProvideService(cfg *setting.Cfg, router routing.RouteRegister, accessContro
}
authorize := ac.Middleware(accessControl)
reqGrafanaAdmin := middleware.ReqGrafanaAdmin
router.Group("/api/admin", func(adminRoute routing.RouteRegister) {
adminRoute.Post("/ldap/reload", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionLDAPConfigReload)), routing.Wrap(s.ReloadLDAPCfg))
adminRoute.Post("/ldap/sync/:id", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionLDAPUsersSync)), routing.Wrap(s.PostSyncUserWithLDAP))
adminRoute.Get("/ldap/:username", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionLDAPUsersRead)), routing.Wrap(s.GetUserFromLDAP))
adminRoute.Get("/ldap/status", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionLDAPStatusRead)), routing.Wrap(s.GetLDAPStatus))
adminRoute.Post("/ldap/reload", authorize(ac.EvalPermission(ac.ActionLDAPConfigReload)), routing.Wrap(s.ReloadLDAPCfg))
adminRoute.Post("/ldap/sync/:id", authorize(ac.EvalPermission(ac.ActionLDAPUsersSync)), routing.Wrap(s.PostSyncUserWithLDAP))
adminRoute.Get("/ldap/:username", authorize(ac.EvalPermission(ac.ActionLDAPUsersRead)), routing.Wrap(s.GetUserFromLDAP))
adminRoute.Get("/ldap/status", authorize(ac.EvalPermission(ac.ActionLDAPStatusRead)), routing.Wrap(s.GetLDAPStatus))
}, middleware.ReqSignedIn)
if cfg.LDAPAuthEnabled {
+1 -24
View File
@@ -24,17 +24,6 @@ func (api *API) authorize(method, path string) web.Handler {
authorize := ac.Middleware(api.AccessControl)
var eval ac.Evaluator = nil
// Most routes follow this general authorization approach as a fallback. Exceptions are overridden directly in the below block.
var fallback web.Handler
switch method {
case http.MethodPost, http.MethodPut, http.MethodDelete:
fallback = middleware.ReqEditorRole
case http.MethodGet:
fallback = middleware.ReqSignedIn
default:
fallback = middleware.ReqSignedIn
}
switch method + path {
// Alert Rules
@@ -50,7 +39,6 @@ func (api *API) authorize(method, path string) web.Handler {
case http.MethodGet + "/api/ruler/grafana/api/v1/rules":
eval = ac.EvalPermission(ac.ActionAlertingRuleRead)
case http.MethodPost + "/api/ruler/grafana/api/v1/rules/{Namespace}":
fallback = middleware.ReqSignedIn // if RBAC is disabled then we need to delegate permission check to folder because its permissions can allow editing for Viewer role
scope := dashboards.ScopeFoldersProvider.GetResourceScopeName(ac.Parameter(":Namespace"))
// more granular permissions are enforced by the handler via "authorizeRuleChanges"
eval = ac.EvalAny(
@@ -60,7 +48,6 @@ func (api *API) authorize(method, path string) web.Handler {
)
// Grafana rule state history paths
case http.MethodGet + "/api/v1/rules/history":
fallback = middleware.ReqSignedIn
eval = ac.EvalPermission(ac.ActionAlertingRuleRead)
// Grafana, Prometheus-compatible Paths
@@ -69,16 +56,13 @@ func (api *API) authorize(method, path string) web.Handler {
// Grafana Rules Testing Paths
case http.MethodPost + "/api/v1/rule/test/grafana":
fallback = middleware.ReqSignedIn
// additional authorization is done in the request handler
eval = ac.EvalPermission(ac.ActionAlertingRuleRead)
// Grafana Rules Testing Paths
case http.MethodPost + "/api/v1/rule/backtest":
fallback = middleware.ReqSignedIn
// additional authorization is done in the request handler
eval = ac.EvalPermission(ac.ActionAlertingRuleRead)
case http.MethodPost + "/api/v1/eval":
fallback = middleware.ReqSignedIn
// additional authorization is done in the request handler
eval = ac.EvalPermission(ac.ActionAlertingRuleRead)
@@ -102,7 +86,6 @@ func (api *API) authorize(method, path string) web.Handler {
// Lotex Rules testing
case http.MethodPost + "/api/v1/rule/test/{DatasourceUID}":
fallback = middleware.ReqSignedIn
eval = ac.EvalPermission(ac.ActionAlertingRuleExternalRead, datasources.ScopeProvider.GetResourceScopeUID(ac.Parameter(":DatasourceUID")))
// Alert Instances and Silences
@@ -156,10 +139,8 @@ func (api *API) authorize(method, path string) web.Handler {
case http.MethodDelete + "/api/alertmanager/grafana/config/api/v1/alerts": // reset alertmanager config to the default
eval = ac.EvalPermission(ac.ActionAlertingNotificationsWrite)
case http.MethodGet + "/api/alertmanager/grafana/config/api/v1/alerts":
fallback = middleware.ReqEditorRole
eval = ac.EvalPermission(ac.ActionAlertingNotificationsRead)
case http.MethodGet + "/api/alertmanager/grafana/config/history":
fallback = middleware.ReqEditorRole
eval = ac.EvalPermission(ac.ActionAlertingNotificationsRead)
case http.MethodGet + "/api/alertmanager/grafana/api/v2/status":
eval = ac.EvalPermission(ac.ActionAlertingNotificationsRead)
@@ -171,10 +152,8 @@ func (api *API) authorize(method, path string) web.Handler {
case http.MethodGet + "/api/alertmanager/grafana/config/api/v1/receivers":
eval = ac.EvalPermission(ac.ActionAlertingNotificationsRead)
case http.MethodPost + "/api/alertmanager/grafana/config/api/v1/receivers/test":
fallback = middleware.ReqEditorRole
eval = ac.EvalPermission(ac.ActionAlertingNotificationsRead)
case http.MethodPost + "/api/alertmanager/grafana/config/api/v1/templates/test":
fallback = middleware.ReqSignedIn
eval = ac.EvalPermission(ac.ActionAlertingNotificationsRead)
// External Alertmanager Paths
@@ -217,7 +196,6 @@ func (api *API) authorize(method, path string) web.Handler {
http.MethodGet + "/api/v1/provisioning/alert-rules/{UID}/export",
http.MethodGet + "/api/v1/provisioning/folder/{FolderUID}/rule-groups/{Group}",
http.MethodGet + "/api/v1/provisioning/folder/{FolderUID}/rule-groups/{Group}/export":
fallback = middleware.ReqOrgAdmin
eval = ac.EvalPermission(ac.ActionAlertingProvisioningRead) // organization scope
case http.MethodPut + "/api/v1/provisioning/policies",
@@ -234,12 +212,11 @@ func (api *API) authorize(method, path string) web.Handler {
http.MethodPut + "/api/v1/provisioning/alert-rules/{UID}",
http.MethodDelete + "/api/v1/provisioning/alert-rules/{UID}",
http.MethodPut + "/api/v1/provisioning/folder/{FolderUID}/rule-groups/{Group}":
fallback = middleware.ReqOrgAdmin
eval = ac.EvalPermission(ac.ActionAlertingProvisioningWrite) // organization scope
}
if eval != nil {
return authorize(fallback, eval)
return authorize(eval)
}
panic(fmt.Sprintf("no authorization handler for method [%s] of endpoint [%s]", method, path))
+4 -4
View File
@@ -68,22 +68,22 @@ func (api *Api) RegisterAPIEndpoints() {
// Get public dashboard
api.RouteRegister.Get("/api/dashboards/uid/:dashboardUid/public-dashboards",
auth(middleware.ReqSignedIn, accesscontrol.EvalPermission(dashboards.ActionDashboardsRead, uidScope)),
auth(accesscontrol.EvalPermission(dashboards.ActionDashboardsRead, uidScope)),
routing.Wrap(api.GetPublicDashboard))
// Create Public Dashboard
api.RouteRegister.Post("/api/dashboards/uid/:dashboardUid/public-dashboards",
auth(middleware.ReqOrgAdmin, accesscontrol.EvalPermission(dashboards.ActionDashboardsPublicWrite, uidScope)),
auth(accesscontrol.EvalPermission(dashboards.ActionDashboardsPublicWrite, uidScope)),
routing.Wrap(api.CreatePublicDashboard))
// Update Public Dashboard
api.RouteRegister.Put("/api/dashboards/uid/:dashboardUid/public-dashboards/:uid",
auth(middleware.ReqOrgAdmin, accesscontrol.EvalPermission(dashboards.ActionDashboardsPublicWrite, uidScope)),
auth(accesscontrol.EvalPermission(dashboards.ActionDashboardsPublicWrite, uidScope)),
routing.Wrap(api.UpdatePublicDashboard))
// Delete Public dashboard
api.RouteRegister.Delete("/api/dashboards/uid/:dashboardUid/public-dashboards/:uid",
auth(middleware.ReqOrgAdmin, accesscontrol.EvalPermission(dashboards.ActionDashboardsPublicWrite, uidScope)),
auth(accesscontrol.EvalPermission(dashboards.ActionDashboardsPublicWrite, uidScope)),
routing.Wrap(api.DeletePublicDashboard))
}
+10 -21
View File
@@ -9,7 +9,6 @@ import (
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/middleware"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/apikey"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
@@ -68,26 +67,16 @@ func NewServiceAccountsAPI(
func (api *ServiceAccountsAPI) RegisterAPIEndpoints() {
auth := accesscontrol.Middleware(api.accesscontrol)
api.RouterRegister.Group("/api/serviceaccounts", func(serviceAccountsRoute routing.RouteRegister) {
serviceAccountsRoute.Get("/search", auth(middleware.ReqOrgAdmin,
accesscontrol.EvalPermission(serviceaccounts.ActionRead)), routing.Wrap(api.SearchOrgServiceAccountsWithPaging))
serviceAccountsRoute.Post("/", auth(middleware.ReqOrgAdmin,
accesscontrol.EvalPermission(serviceaccounts.ActionCreate)), routing.Wrap(api.CreateServiceAccount))
serviceAccountsRoute.Get("/:serviceAccountId", auth(middleware.ReqOrgAdmin,
accesscontrol.EvalPermission(serviceaccounts.ActionRead, serviceaccounts.ScopeID)), routing.Wrap(api.RetrieveServiceAccount))
serviceAccountsRoute.Patch("/:serviceAccountId", auth(middleware.ReqOrgAdmin,
accesscontrol.EvalPermission(serviceaccounts.ActionWrite, serviceaccounts.ScopeID)), routing.Wrap(api.UpdateServiceAccount))
serviceAccountsRoute.Delete("/:serviceAccountId", auth(middleware.ReqOrgAdmin,
accesscontrol.EvalPermission(serviceaccounts.ActionDelete, serviceaccounts.ScopeID)), routing.Wrap(api.DeleteServiceAccount))
serviceAccountsRoute.Get("/:serviceAccountId/tokens", auth(middleware.ReqOrgAdmin,
accesscontrol.EvalPermission(serviceaccounts.ActionRead, serviceaccounts.ScopeID)), routing.Wrap(api.ListTokens))
serviceAccountsRoute.Post("/:serviceAccountId/tokens", auth(middleware.ReqOrgAdmin,
accesscontrol.EvalPermission(serviceaccounts.ActionWrite, serviceaccounts.ScopeID)), routing.Wrap(api.CreateToken))
serviceAccountsRoute.Delete("/:serviceAccountId/tokens/:tokenId", auth(middleware.ReqOrgAdmin,
accesscontrol.EvalPermission(serviceaccounts.ActionWrite, serviceaccounts.ScopeID)), routing.Wrap(api.DeleteToken))
serviceAccountsRoute.Post("/migrate", auth(middleware.ReqOrgAdmin,
accesscontrol.EvalPermission(serviceaccounts.ActionCreate)), routing.Wrap(api.MigrateApiKeysToServiceAccounts))
serviceAccountsRoute.Post("/migrate/:keyId", auth(middleware.ReqOrgAdmin,
accesscontrol.EvalPermission(serviceaccounts.ActionCreate)), routing.Wrap(api.ConvertToServiceAccount))
serviceAccountsRoute.Get("/search", auth(accesscontrol.EvalPermission(serviceaccounts.ActionRead)), routing.Wrap(api.SearchOrgServiceAccountsWithPaging))
serviceAccountsRoute.Post("/", auth(accesscontrol.EvalPermission(serviceaccounts.ActionCreate)), routing.Wrap(api.CreateServiceAccount))
serviceAccountsRoute.Get("/:serviceAccountId", auth(accesscontrol.EvalPermission(serviceaccounts.ActionRead, serviceaccounts.ScopeID)), routing.Wrap(api.RetrieveServiceAccount))
serviceAccountsRoute.Patch("/:serviceAccountId", auth(accesscontrol.EvalPermission(serviceaccounts.ActionWrite, serviceaccounts.ScopeID)), routing.Wrap(api.UpdateServiceAccount))
serviceAccountsRoute.Delete("/:serviceAccountId", auth(accesscontrol.EvalPermission(serviceaccounts.ActionDelete, serviceaccounts.ScopeID)), routing.Wrap(api.DeleteServiceAccount))
serviceAccountsRoute.Get("/:serviceAccountId/tokens", auth(accesscontrol.EvalPermission(serviceaccounts.ActionRead, serviceaccounts.ScopeID)), routing.Wrap(api.ListTokens))
serviceAccountsRoute.Post("/:serviceAccountId/tokens", auth(accesscontrol.EvalPermission(serviceaccounts.ActionWrite, serviceaccounts.ScopeID)), routing.Wrap(api.CreateToken))
serviceAccountsRoute.Delete("/:serviceAccountId/tokens/:tokenId", auth(accesscontrol.EvalPermission(serviceaccounts.ActionWrite, serviceaccounts.ScopeID)), routing.Wrap(api.DeleteToken))
serviceAccountsRoute.Post("/migrate", auth(accesscontrol.EvalPermission(serviceaccounts.ActionCreate)), routing.Wrap(api.MigrateApiKeysToServiceAccounts))
serviceAccountsRoute.Post("/migrate/:keyId", auth(accesscontrol.EvalPermission(serviceaccounts.ActionCreate)), routing.Wrap(api.ConvertToServiceAccount))
})
}
@@ -9,8 +9,6 @@ import (
grafanaApi "github.com/grafana/grafana/pkg/api"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/middleware"
"github.com/grafana/grafana/pkg/models/roletype"
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
"github.com/grafana/grafana/pkg/services/supportbundles"
@@ -22,30 +20,20 @@ const rootUrl = "/api/support-bundles"
func (s *Service) registerAPIEndpoints(httpServer *grafanaApi.HTTPServer, routeRegister routing.RouteRegister) {
authorize := ac.Middleware(s.accessControl)
orgRoleMiddleware := middleware.ReqGrafanaAdmin
if !s.serverAdminOnly {
orgRoleMiddleware = middleware.RoleAuth(roletype.RoleAdmin)
}
supportBundlePageAccess := ac.EvalAny(
ac.EvalPermission(ActionRead),
ac.EvalPermission(ActionCreate),
)
routeRegister.Get("/support-bundles", authorize(orgRoleMiddleware, supportBundlePageAccess), httpServer.Index)
routeRegister.Get("/support-bundles/create", authorize(orgRoleMiddleware, ac.EvalPermission(ActionCreate)), httpServer.Index)
routeRegister.Get("/support-bundles", authorize(supportBundlePageAccess), httpServer.Index)
routeRegister.Get("/support-bundles/create", authorize(ac.EvalPermission(ActionCreate)), httpServer.Index)
routeRegister.Group(rootUrl, func(subrouter routing.RouteRegister) {
subrouter.Get("/", authorize(orgRoleMiddleware,
ac.EvalPermission(ActionRead)), routing.Wrap(s.handleList))
subrouter.Post("/", authorize(orgRoleMiddleware,
ac.EvalPermission(ActionCreate)), routing.Wrap(s.handleCreate))
subrouter.Get("/:uid", authorize(orgRoleMiddleware,
ac.EvalPermission(ActionRead)), s.handleDownload)
subrouter.Delete("/:uid", authorize(orgRoleMiddleware,
ac.EvalPermission(ActionDelete)), s.handleRemove)
subrouter.Get("/collectors", authorize(orgRoleMiddleware,
ac.EvalPermission(ActionCreate)), routing.Wrap(s.handleGetCollectors))
subrouter.Get("/", authorize(ac.EvalPermission(ActionRead)), routing.Wrap(s.handleList))
subrouter.Post("/", authorize(ac.EvalPermission(ActionCreate)), routing.Wrap(s.handleCreate))
subrouter.Get("/:uid", authorize(ac.EvalPermission(ActionRead)), s.handleDownload)
subrouter.Delete("/:uid", authorize(ac.EvalPermission(ActionDelete)), s.handleRemove)
subrouter.Get("/collectors", authorize(ac.EvalPermission(ActionCreate)), routing.Wrap(s.handleGetCollectors))
})
}
-4
View File
@@ -98,10 +98,6 @@ type SearchTeamQueryResult struct {
PerPage int `json:"perPage"`
}
type IsAdminOfTeamsQuery struct {
SignedInUser *user.SignedInUser
}
// TeamMember model
type TeamMember struct {
ID int64 `xorm:"pk autoincr 'id'"`
-1
View File
@@ -20,5 +20,4 @@ type Service interface {
RemoveUsersMemberships(tx context.Context, userID int64) error
GetUserTeamMemberships(ctx context.Context, orgID, userID int64, external bool) ([]*TeamMemberDTO, error)
GetTeamMembers(ctx context.Context, query *GetTeamMembersQuery) ([]*TeamMemberDTO, error)
IsAdminOfTeams(ctx context.Context, query *IsAdminOfTeamsQuery) (bool, error)
}
-34
View File
@@ -30,7 +30,6 @@ type store interface {
RemoveMember(ctx context.Context, cmd *team.RemoveTeamMemberCommand) error
GetMemberships(ctx context.Context, orgID, userID int64, external bool) ([]*team.TeamMemberDTO, error)
GetMembers(ctx context.Context, query *team.GetTeamMembersQuery) ([]*team.TeamMemberDTO, error)
IsAdmin(ctx context.Context, query *team.IsAdminOfTeamsQuery) (bool, error)
}
type xormStore struct {
@@ -558,36 +557,3 @@ func (ss *xormStore) getTeamMembers(ctx context.Context, query *team.GetTeamMemb
}
return queryResult, nil
}
func (ss *xormStore) IsAdmin(ctx context.Context, query *team.IsAdminOfTeamsQuery) (bool, error) {
queryResult := false
err := ss.db.WithDbSession(ctx, func(sess *db.Session) error {
sql := `SELECT COUNT(team.id) AS count
FROM team
INNER JOIN team_member ON team_member.team_id = team.id
WHERE team.org_id = ?
AND team_member.user_id = ?
AND team_member.permission = ?`
params := []interface{}{
query.SignedInUser.OrgID,
query.SignedInUser.UserID,
dashboards.PERMISSION_ADMIN,
}
type teamCount struct {
Count int64
}
resp := make([]*teamCount, 0)
if err := sess.SQL(sql, params...).Find(&resp); err != nil {
return err
}
queryResult = len(resp) > 0 && resp[0].Count > 0
return nil
})
return queryResult, err
}
-20
View File
@@ -319,26 +319,6 @@ func TestIntegrationTeamCommandsAndQueries(t *testing.T) {
require.Equal(t, len(permQueryResult), 0)
})
t.Run("Should be able to return if user is admin of teams or not", func(t *testing.T) {
sqlStore = db.InitTestDB(t)
setup()
groupId := team2.ID
err := teamSvc.AddTeamMember(userIds[0], testOrgID, groupId, false, 0)
require.NoError(t, err)
err = teamSvc.AddTeamMember(userIds[1], testOrgID, groupId, false, dashboards.PERMISSION_ADMIN)
require.NoError(t, err)
query := &team.IsAdminOfTeamsQuery{SignedInUser: &user.SignedInUser{OrgID: testOrgID, UserID: userIds[0]}}
queryResult, err := teamSvc.IsAdminOfTeams(context.Background(), query)
require.NoError(t, err)
require.False(t, queryResult)
query = &team.IsAdminOfTeamsQuery{SignedInUser: &user.SignedInUser{OrgID: testOrgID, UserID: userIds[1]}}
queryResult, err = teamSvc.IsAdminOfTeams(context.Background(), query)
require.NoError(t, err)
require.True(t, queryResult)
})
t.Run("Should not return hidden users in team member count", func(t *testing.T) {
sqlStore = db.InitTestDB(t)
setup()
-4
View File
@@ -68,7 +68,3 @@ func (s *Service) GetUserTeamMemberships(ctx context.Context, orgID, userID int6
func (s *Service) GetTeamMembers(ctx context.Context, query *team.GetTeamMembersQuery) ([]*team.TeamMemberDTO, error) {
return s.store.GetMembers(ctx, query)
}
func (s *Service) IsAdminOfTeams(ctx context.Context, query *team.IsAdminOfTeamsQuery) (bool, error) {
return s.store.IsAdmin(ctx, query)
}
-4
View File
@@ -72,7 +72,3 @@ func (s *FakeService) GetUserTeamMemberships(ctx context.Context, orgID, userID
func (s *FakeService) GetTeamMembers(ctx context.Context, query *team.GetTeamMembersQuery) ([]*team.TeamMemberDTO, error) {
return s.ExpectedMembers, s.ExpectedError
}
func (s *FakeService) IsAdminOfTeams(ctx context.Context, query *team.IsAdminOfTeamsQuery) (bool, error) {
return s.ExpectedIsAdmin, s.ExpectedError
}