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:
@@ -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))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) {}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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'"`
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user