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

Commit a79cffe

Browse files
author
Aaron Godin
committed
feat: Add methods for managing RBAC assignment through resource permissions endpoints
1 parent 6d42666 commit a79cffe

11 files changed

+424
-40
lines changed

dashboard_permissions.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,56 @@ func (c *Client) UpdateDashboardPermissionsByUID(uid string, items *PermissionIt
5858

5959
return c.request("POST", path, nil, data, nil)
6060
}
61+
62+
func (c *Client) ListDashboardResourcePermissions(ident ResourceIdent) ([]*ResourcePermission, error) {
63+
return c.listResourcePermissions("dashboards", ident)
64+
}
65+
66+
func (c *Client) SetDashboardResourcePermissions(ident ResourceIdent, body SetResourcePermissionsBody) (*SetResourcePermissionsResponse, error) {
67+
return c.setResourcePermissions("dashboards", ident, body)
68+
}
69+
70+
func (c *Client) SetUserDashboardResourcePermissions(ident ResourceIdent, userID int64, permission string) (*SetResourcePermissionsResponse, error) {
71+
return c.setResourcePermissionByAssignment(
72+
"dashboards",
73+
ident,
74+
"users",
75+
ResourceID(userID),
76+
SetResourcePermissionBody{
77+
Permission: SetResourcePermissionItem{
78+
UserID: userID,
79+
Permission: permission,
80+
},
81+
},
82+
)
83+
}
84+
85+
func (c *Client) SetTeamDashboardResourcePermissions(ident ResourceIdent, teamID int64, permission string) (*SetResourcePermissionsResponse, error) {
86+
return c.setResourcePermissionByAssignment(
87+
"dashboards",
88+
ident,
89+
"teams",
90+
ResourceID(teamID),
91+
SetResourcePermissionBody{
92+
Permission: SetResourcePermissionItem{
93+
TeamID: teamID,
94+
Permission: permission,
95+
},
96+
},
97+
)
98+
}
99+
100+
func (c *Client) SetBuiltInRoleDashboardResourcePermissions(ident ResourceIdent, builtInRole string, permission string) (*SetResourcePermissionsResponse, error) {
101+
return c.setResourcePermissionByAssignment(
102+
"dashboards",
103+
ident,
104+
"builtInRoles",
105+
ResourceUID(builtInRole),
106+
SetResourcePermissionBody{
107+
Permission: SetResourcePermissionItem{
108+
BuiltinRole: builtInRole,
109+
Permission: permission,
110+
},
111+
},
112+
)
113+
}

datasource_permissions.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,56 @@ func (c *Client) RemoveDatasourcePermission(id, permissionID int64) error {
9696

9797
return nil
9898
}
99+
100+
func (c *Client) ListDatasourceResourcePermissions(ident ResourceIdent) ([]*ResourcePermission, error) {
101+
return c.listResourcePermissions("datasources", ident)
102+
}
103+
104+
func (c *Client) SetDatasourceResourcePermissions(ident ResourceIdent, body SetResourcePermissionsBody) (*SetResourcePermissionsResponse, error) {
105+
return c.setResourcePermissions("datasources", ident, body)
106+
}
107+
108+
func (c *Client) SetUserDatasourceResourcePermissions(ident ResourceIdent, userID int64, permission string) (*SetResourcePermissionsResponse, error) {
109+
return c.setResourcePermissionByAssignment(
110+
"datasources",
111+
ident,
112+
"users",
113+
ResourceID(userID),
114+
SetResourcePermissionBody{
115+
Permission: SetResourcePermissionItem{
116+
UserID: userID,
117+
Permission: permission,
118+
},
119+
},
120+
)
121+
}
122+
123+
func (c *Client) SetTeamDatasourceResourcePermissions(ident ResourceIdent, teamID int64, permission string) (*SetResourcePermissionsResponse, error) {
124+
return c.setResourcePermissionByAssignment(
125+
"datasources",
126+
ident,
127+
"teams",
128+
ResourceID(teamID),
129+
SetResourcePermissionBody{
130+
Permission: SetResourcePermissionItem{
131+
TeamID: teamID,
132+
Permission: permission,
133+
},
134+
},
135+
)
136+
}
137+
138+
func (c *Client) SetBuiltInRoleDatasourceResourcePermissions(ident ResourceIdent, builtInRole string, permission string) (*SetResourcePermissionsResponse, error) {
139+
return c.setResourcePermissionByAssignment(
140+
"datasources",
141+
ident,
142+
"builtInRoles",
143+
ResourceUID(builtInRole),
144+
SetResourcePermissionBody{
145+
Permission: SetResourcePermissionItem{
146+
BuiltinRole: builtInRole,
147+
Permission: permission,
148+
},
149+
},
150+
)
151+
}

folder_permissions.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,56 @@ func (c *Client) UpdateFolderPermissions(fid string, items *PermissionItems) err
6262

6363
return c.request("POST", path, nil, data, nil)
6464
}
65+
66+
func (c *Client) ListFolderResourcePermissions(ident ResourceIdent) ([]*ResourcePermission, error) {
67+
return c.listResourcePermissions("folders", ident)
68+
}
69+
70+
func (c *Client) SetFolderResourcePermissions(ident ResourceIdent, body SetResourcePermissionsBody) (*SetResourcePermissionsResponse, error) {
71+
return c.setResourcePermissions("folders", ident, body)
72+
}
73+
74+
func (c *Client) SetUserFolderResourcePermissions(ident ResourceIdent, userID int64, permission string) (*SetResourcePermissionsResponse, error) {
75+
return c.setResourcePermissionByAssignment(
76+
"folders",
77+
ident,
78+
"users",
79+
ResourceID(userID),
80+
SetResourcePermissionBody{
81+
Permission: SetResourcePermissionItem{
82+
UserID: userID,
83+
Permission: permission,
84+
},
85+
},
86+
)
87+
}
88+
89+
func (c *Client) SetTeamFolderResourcePermissions(ident ResourceIdent, teamID int64, permission string) (*SetResourcePermissionsResponse, error) {
90+
return c.setResourcePermissionByAssignment(
91+
"folders",
92+
ident,
93+
"teams",
94+
ResourceID(teamID),
95+
SetResourcePermissionBody{
96+
Permission: SetResourcePermissionItem{
97+
TeamID: teamID,
98+
Permission: permission,
99+
},
100+
},
101+
)
102+
}
103+
104+
func (c *Client) SetBuiltInRoleFolderResourcePermissions(ident ResourceIdent, builtInRole string, permission string) (*SetResourcePermissionsResponse, error) {
105+
return c.setResourcePermissionByAssignment(
106+
"folders",
107+
ident,
108+
"builtInRoles",
109+
ResourceUID(builtInRole),
110+
SetResourcePermissionBody{
111+
Permission: SetResourcePermissionItem{
112+
BuiltinRole: builtInRole,
113+
Permission: permission,
114+
},
115+
},
116+
)
117+
}

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ go 1.14
55
require (
66
github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b
77
github.com/hashicorp/go-cleanhttp v0.5.2
8+
github.com/stretchr/testify v1.8.4
89
)

go.sum

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,21 @@
1+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
3+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
14
github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b h1:/vQ+oYKu+JoyaMPDsv5FzwuL2wwWBgBbtj/YLCi4LuA=
25
github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b/go.mod h1:Xo4aNUOrJnVruqWQJBtW6+bTBDTniY8yZum5rF3b5jw=
36
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
47
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
8+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
9+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
10+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
11+
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
12+
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
13+
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
14+
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
15+
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
16+
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
17+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
18+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
19+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
20+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
21+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

resource.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package gapi
2+
3+
import (
4+
"fmt"
5+
"strconv"
6+
)
7+
8+
// ResourceIdent represents anything that can be considered a resource identifier.
9+
type ResourceIdent interface {
10+
fmt.Stringer
11+
}
12+
13+
// ResourceID wraps `int64` to be a valid `ResourceIdent`
14+
type ResourceID int64
15+
16+
func (id ResourceID) String() string {
17+
return strconv.FormatInt(int64(id), 10)
18+
}
19+
20+
// ResourceUID wraps `string` to be a valid `ResourceIdent`
21+
type ResourceUID string
22+
23+
func (id ResourceUID) String() string {
24+
return string(id)
25+
}

resource_permissions.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package gapi
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
)
7+
8+
type ResourcePermission struct {
9+
ID int64 `json:"id"`
10+
RoleName string `json:"roleName"`
11+
IsManaged bool `json:"isManaged"`
12+
IsInherited bool `json:"isInherited"`
13+
IsServiceAccount bool `json:"isServiceAccount"`
14+
UserID int64 `json:"userId,omitempty"`
15+
UserLogin string `json:"userLogin,omitempty"`
16+
UserAvatarURL string `json:"userAvatarUrl,omitempty"`
17+
Team string `json:"team,omitempty"`
18+
TeamID int64 `json:"teamId,omitempty"`
19+
TeamAvatarUrl string `json:"teamAvatarUrl,omitempty"`
20+
BuiltInRole string `json:"builtInRole,omitempty"`
21+
Actions []string `json:"actions"`
22+
Permission string `json:"permission"`
23+
}
24+
25+
type SetResourcePermissionsBody struct {
26+
Permissions []SetResourcePermissionItem `json:"permissions"`
27+
}
28+
29+
type SetResourcePermissionBody struct {
30+
Permission SetResourcePermissionItem `json:"permission"`
31+
}
32+
33+
type SetResourcePermissionItem struct {
34+
UserID int64 `json:"userId,omitempty"`
35+
TeamID int64 `json:"teamId,omitempty"`
36+
BuiltinRole string `json:"builtInRole,omitempty"`
37+
Permission string `json:"permission"`
38+
}
39+
40+
type SetResourcePermissionsResponse struct {
41+
Message string `json:"message"`
42+
}
43+
44+
func (c *Client) listResourcePermissions(resource string, ident ResourceIdent) ([]*ResourcePermission, error) {
45+
path := fmt.Sprintf("/api/access-control/%s/%s", resource, ident.String())
46+
result := make([]*ResourcePermission, 0)
47+
if err := c.request("GET", path, nil, nil, &result); err != nil {
48+
return nil, fmt.Errorf("error getting %s resource permissions at %s: %w", resource, path, err)
49+
}
50+
return result, nil
51+
}
52+
53+
func (c *Client) setResourcePermissions(resource string, ident ResourceIdent, body SetResourcePermissionsBody) (*SetResourcePermissionsResponse, error) {
54+
path := fmt.Sprintf("/api/access-control/%s/%s", resource, ident.String())
55+
data, err := json.Marshal(body)
56+
if err != nil {
57+
return nil, fmt.Errorf("marshal err: %w", err)
58+
}
59+
60+
result := SetResourcePermissionsResponse{}
61+
if err := c.request("POST", path, nil, data, &result); err != nil {
62+
return nil, fmt.Errorf("error setting %s resource permissions at %s: %w", resource, path, err)
63+
}
64+
return &result, nil
65+
}
66+
67+
func (c *Client) setResourcePermissionByAssignment(
68+
resource string,
69+
ident ResourceIdent,
70+
assignmentKind string,
71+
assignmentIdent ResourceIdent,
72+
body SetResourcePermissionBody,
73+
) (*SetResourcePermissionsResponse, error) {
74+
path := fmt.Sprintf("/api/access-control/%s/%s/%s/%s", resource, ident.String(), assignmentKind, assignmentIdent.String())
75+
data, err := json.Marshal(body)
76+
if err != nil {
77+
return nil, fmt.Errorf("marshal err: %w", err)
78+
}
79+
80+
result := SetResourcePermissionsResponse{}
81+
if err := c.request("POST", path, nil, data, &result); err != nil {
82+
return nil, fmt.Errorf("error setting %s resource permissions for %s at %s: %w", resource, assignmentKind, path, err)
83+
}
84+
return &result, nil
85+
}

resource_permissions_test.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package gapi
2+
3+
import (
4+
"net/http"
5+
"testing"
6+
7+
"github.com/gobs/pretty"
8+
)
9+
10+
const (
11+
resourcePermissionsListJSON = `[
12+
{
13+
"id": 1,
14+
"roleName": "basic:admin",
15+
"isManaged": false,
16+
"isInherited": false,
17+
"isServiceAccount": false,
18+
"builtInRole": "Admin",
19+
"actions": [
20+
"datasources:delete",
21+
"datasources:query",
22+
"datasources:read",
23+
"datasources:write",
24+
"datasources.caching:read",
25+
"datasources.caching:write",
26+
"datasources.permissions:read",
27+
"datasources.permissions:write"
28+
],
29+
"permission": "Admin"
30+
}
31+
]`
32+
resourcePermissionsResponseJSON = `{"message":"Permissions updated"}`
33+
)
34+
35+
func TestListResourcePermissions(t *testing.T) {
36+
client := gapiTestTools(t, http.StatusOK, resourcePermissionsListJSON)
37+
res, err := client.listResourcePermissions("datasources", ResourceID(1))
38+
if err != nil {
39+
t.Error(err)
40+
}
41+
t.Log(pretty.PrettyFormat(res))
42+
}
43+
44+
func TestSetResourcePermissions(t *testing.T) {
45+
client := gapiTestTools(t, http.StatusOK, resourcePermissionsResponseJSON)
46+
res, err := client.setResourcePermissions("datasources", ResourceID(1), SetResourcePermissionsBody{
47+
Permissions: []SetResourcePermissionItem{
48+
{
49+
UserID: 1,
50+
Permission: "View",
51+
},
52+
},
53+
})
54+
if err != nil {
55+
t.Error(err)
56+
}
57+
t.Log(pretty.PrettyFormat(res))
58+
}
59+
60+
func TestSetResourcePermissionsByAssignment(t *testing.T) {
61+
client := gapiTestTools(t, http.StatusOK, resourcePermissionsResponseJSON)
62+
res, err := client.setResourcePermissionByAssignment("datasources", ResourceID(1), "users", ResourceID(1), SetResourcePermissionBody{
63+
Permission: SetResourcePermissionItem{
64+
Permission: "View",
65+
},
66+
})
67+
if err != nil {
68+
t.Error(err)
69+
}
70+
t.Log(pretty.PrettyFormat(res))
71+
}

resource_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package gapi
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
)
8+
9+
func TestResourceIdent(t *testing.T) {
10+
require.Equal(t, "1", ResourceID(1).String())
11+
require.Equal(t, ResourceUID("testing").String(), "testing")
12+
}

0 commit comments

Comments
 (0)