Skip to content
This repository has been archived by the owner on Jan 15, 2024. It is now read-only.

Commit

Permalink
feat: Add methods for managing RBAC assignment through resource permi…
Browse files Browse the repository at this point in the history
…ssions endpoints
  • Loading branch information
Aaron Godin committed Nov 1, 2023
1 parent 6d42666 commit a79cffe
Show file tree
Hide file tree
Showing 11 changed files with 424 additions and 40 deletions.
53 changes: 53 additions & 0 deletions dashboard_permissions.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,56 @@ func (c *Client) UpdateDashboardPermissionsByUID(uid string, items *PermissionIt

return c.request("POST", path, nil, data, nil)
}

func (c *Client) ListDashboardResourcePermissions(ident ResourceIdent) ([]*ResourcePermission, error) {
return c.listResourcePermissions("dashboards", ident)
}

func (c *Client) SetDashboardResourcePermissions(ident ResourceIdent, body SetResourcePermissionsBody) (*SetResourcePermissionsResponse, error) {
return c.setResourcePermissions("dashboards", ident, body)
}

func (c *Client) SetUserDashboardResourcePermissions(ident ResourceIdent, userID int64, permission string) (*SetResourcePermissionsResponse, error) {
return c.setResourcePermissionByAssignment(
"dashboards",
ident,
"users",
ResourceID(userID),
SetResourcePermissionBody{
Permission: SetResourcePermissionItem{
UserID: userID,
Permission: permission,
},
},
)
}

func (c *Client) SetTeamDashboardResourcePermissions(ident ResourceIdent, teamID int64, permission string) (*SetResourcePermissionsResponse, error) {
return c.setResourcePermissionByAssignment(
"dashboards",
ident,
"teams",
ResourceID(teamID),
SetResourcePermissionBody{
Permission: SetResourcePermissionItem{
TeamID: teamID,
Permission: permission,
},
},
)
}

func (c *Client) SetBuiltInRoleDashboardResourcePermissions(ident ResourceIdent, builtInRole string, permission string) (*SetResourcePermissionsResponse, error) {
return c.setResourcePermissionByAssignment(
"dashboards",
ident,
"builtInRoles",
ResourceUID(builtInRole),
SetResourcePermissionBody{
Permission: SetResourcePermissionItem{
BuiltinRole: builtInRole,
Permission: permission,
},
},
)
}
53 changes: 53 additions & 0 deletions datasource_permissions.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,56 @@ func (c *Client) RemoveDatasourcePermission(id, permissionID int64) error {

return nil
}

func (c *Client) ListDatasourceResourcePermissions(ident ResourceIdent) ([]*ResourcePermission, error) {
return c.listResourcePermissions("datasources", ident)
}

func (c *Client) SetDatasourceResourcePermissions(ident ResourceIdent, body SetResourcePermissionsBody) (*SetResourcePermissionsResponse, error) {
return c.setResourcePermissions("datasources", ident, body)
}

func (c *Client) SetUserDatasourceResourcePermissions(ident ResourceIdent, userID int64, permission string) (*SetResourcePermissionsResponse, error) {
return c.setResourcePermissionByAssignment(
"datasources",
ident,
"users",
ResourceID(userID),
SetResourcePermissionBody{
Permission: SetResourcePermissionItem{
UserID: userID,
Permission: permission,
},
},
)
}

func (c *Client) SetTeamDatasourceResourcePermissions(ident ResourceIdent, teamID int64, permission string) (*SetResourcePermissionsResponse, error) {
return c.setResourcePermissionByAssignment(
"datasources",
ident,
"teams",
ResourceID(teamID),
SetResourcePermissionBody{
Permission: SetResourcePermissionItem{
TeamID: teamID,
Permission: permission,
},
},
)
}

func (c *Client) SetBuiltInRoleDatasourceResourcePermissions(ident ResourceIdent, builtInRole string, permission string) (*SetResourcePermissionsResponse, error) {
return c.setResourcePermissionByAssignment(
"datasources",
ident,
"builtInRoles",
ResourceUID(builtInRole),
SetResourcePermissionBody{
Permission: SetResourcePermissionItem{
BuiltinRole: builtInRole,
Permission: permission,
},
},
)
}
53 changes: 53 additions & 0 deletions folder_permissions.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,56 @@ func (c *Client) UpdateFolderPermissions(fid string, items *PermissionItems) err

return c.request("POST", path, nil, data, nil)
}

func (c *Client) ListFolderResourcePermissions(ident ResourceIdent) ([]*ResourcePermission, error) {
return c.listResourcePermissions("folders", ident)
}

func (c *Client) SetFolderResourcePermissions(ident ResourceIdent, body SetResourcePermissionsBody) (*SetResourcePermissionsResponse, error) {
return c.setResourcePermissions("folders", ident, body)
}

func (c *Client) SetUserFolderResourcePermissions(ident ResourceIdent, userID int64, permission string) (*SetResourcePermissionsResponse, error) {
return c.setResourcePermissionByAssignment(
"folders",
ident,
"users",
ResourceID(userID),
SetResourcePermissionBody{
Permission: SetResourcePermissionItem{
UserID: userID,
Permission: permission,
},
},
)
}

func (c *Client) SetTeamFolderResourcePermissions(ident ResourceIdent, teamID int64, permission string) (*SetResourcePermissionsResponse, error) {
return c.setResourcePermissionByAssignment(
"folders",
ident,
"teams",
ResourceID(teamID),
SetResourcePermissionBody{
Permission: SetResourcePermissionItem{
TeamID: teamID,
Permission: permission,
},
},
)
}

func (c *Client) SetBuiltInRoleFolderResourcePermissions(ident ResourceIdent, builtInRole string, permission string) (*SetResourcePermissionsResponse, error) {
return c.setResourcePermissionByAssignment(
"folders",
ident,
"builtInRoles",
ResourceUID(builtInRole),
SetResourcePermissionBody{
Permission: SetResourcePermissionItem{
BuiltinRole: builtInRole,
Permission: permission,
},
},
)
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ go 1.14
require (
github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b
github.com/hashicorp/go-cleanhttp v0.5.2
github.com/stretchr/testify v1.8.4
)
17 changes: 17 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,4 +1,21 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b h1:/vQ+oYKu+JoyaMPDsv5FzwuL2wwWBgBbtj/YLCi4LuA=
github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b/go.mod h1:Xo4aNUOrJnVruqWQJBtW6+bTBDTniY8yZum5rF3b5jw=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
25 changes: 25 additions & 0 deletions resource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package gapi

import (
"fmt"
"strconv"
)

// ResourceIdent represents anything that can be considered a resource identifier.
type ResourceIdent interface {
fmt.Stringer
}

// ResourceID wraps `int64` to be a valid `ResourceIdent`
type ResourceID int64

func (id ResourceID) String() string {
return strconv.FormatInt(int64(id), 10)
}

// ResourceUID wraps `string` to be a valid `ResourceIdent`
type ResourceUID string

func (id ResourceUID) String() string {
return string(id)
}
85 changes: 85 additions & 0 deletions resource_permissions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package gapi

import (
"encoding/json"
"fmt"
)

type ResourcePermission struct {
ID int64 `json:"id"`
RoleName string `json:"roleName"`
IsManaged bool `json:"isManaged"`
IsInherited bool `json:"isInherited"`
IsServiceAccount bool `json:"isServiceAccount"`
UserID int64 `json:"userId,omitempty"`
UserLogin string `json:"userLogin,omitempty"`
UserAvatarURL string `json:"userAvatarUrl,omitempty"`
Team string `json:"team,omitempty"`
TeamID int64 `json:"teamId,omitempty"`
TeamAvatarUrl string `json:"teamAvatarUrl,omitempty"`
BuiltInRole string `json:"builtInRole,omitempty"`
Actions []string `json:"actions"`
Permission string `json:"permission"`
}

type SetResourcePermissionsBody struct {
Permissions []SetResourcePermissionItem `json:"permissions"`
}

type SetResourcePermissionBody struct {
Permission SetResourcePermissionItem `json:"permission"`
}

type SetResourcePermissionItem struct {
UserID int64 `json:"userId,omitempty"`
TeamID int64 `json:"teamId,omitempty"`
BuiltinRole string `json:"builtInRole,omitempty"`
Permission string `json:"permission"`
}

type SetResourcePermissionsResponse struct {
Message string `json:"message"`
}

func (c *Client) listResourcePermissions(resource string, ident ResourceIdent) ([]*ResourcePermission, error) {
path := fmt.Sprintf("/api/access-control/%s/%s", resource, ident.String())
result := make([]*ResourcePermission, 0)
if err := c.request("GET", path, nil, nil, &result); err != nil {
return nil, fmt.Errorf("error getting %s resource permissions at %s: %w", resource, path, err)
}
return result, nil
}

func (c *Client) setResourcePermissions(resource string, ident ResourceIdent, body SetResourcePermissionsBody) (*SetResourcePermissionsResponse, error) {
path := fmt.Sprintf("/api/access-control/%s/%s", resource, ident.String())
data, err := json.Marshal(body)
if err != nil {
return nil, fmt.Errorf("marshal err: %w", err)
}

result := SetResourcePermissionsResponse{}
if err := c.request("POST", path, nil, data, &result); err != nil {
return nil, fmt.Errorf("error setting %s resource permissions at %s: %w", resource, path, err)
}
return &result, nil
}

func (c *Client) setResourcePermissionByAssignment(
resource string,
ident ResourceIdent,
assignmentKind string,
assignmentIdent ResourceIdent,
body SetResourcePermissionBody,
) (*SetResourcePermissionsResponse, error) {
path := fmt.Sprintf("/api/access-control/%s/%s/%s/%s", resource, ident.String(), assignmentKind, assignmentIdent.String())
data, err := json.Marshal(body)
if err != nil {
return nil, fmt.Errorf("marshal err: %w", err)
}

result := SetResourcePermissionsResponse{}
if err := c.request("POST", path, nil, data, &result); err != nil {
return nil, fmt.Errorf("error setting %s resource permissions for %s at %s: %w", resource, assignmentKind, path, err)
}
return &result, nil
}
71 changes: 71 additions & 0 deletions resource_permissions_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package gapi

import (
"net/http"
"testing"

"github.com/gobs/pretty"
)

const (
resourcePermissionsListJSON = `[
{
"id": 1,
"roleName": "basic:admin",
"isManaged": false,
"isInherited": false,
"isServiceAccount": false,
"builtInRole": "Admin",
"actions": [
"datasources:delete",
"datasources:query",
"datasources:read",
"datasources:write",
"datasources.caching:read",
"datasources.caching:write",
"datasources.permissions:read",
"datasources.permissions:write"
],
"permission": "Admin"
}
]`
resourcePermissionsResponseJSON = `{"message":"Permissions updated"}`
)

func TestListResourcePermissions(t *testing.T) {
client := gapiTestTools(t, http.StatusOK, resourcePermissionsListJSON)
res, err := client.listResourcePermissions("datasources", ResourceID(1))
if err != nil {
t.Error(err)
}
t.Log(pretty.PrettyFormat(res))
}

func TestSetResourcePermissions(t *testing.T) {
client := gapiTestTools(t, http.StatusOK, resourcePermissionsResponseJSON)
res, err := client.setResourcePermissions("datasources", ResourceID(1), SetResourcePermissionsBody{
Permissions: []SetResourcePermissionItem{
{
UserID: 1,
Permission: "View",
},
},
})
if err != nil {
t.Error(err)
}
t.Log(pretty.PrettyFormat(res))
}

func TestSetResourcePermissionsByAssignment(t *testing.T) {
client := gapiTestTools(t, http.StatusOK, resourcePermissionsResponseJSON)
res, err := client.setResourcePermissionByAssignment("datasources", ResourceID(1), "users", ResourceID(1), SetResourcePermissionBody{
Permission: SetResourcePermissionItem{
Permission: "View",
},
})
if err != nil {
t.Error(err)
}
t.Log(pretty.PrettyFormat(res))
}
12 changes: 12 additions & 0 deletions resource_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package gapi

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestResourceIdent(t *testing.T) {
require.Equal(t, "1", ResourceID(1).String())
require.Equal(t, ResourceUID("testing").String(), "testing")
}
Loading

0 comments on commit a79cffe

Please sign in to comment.