-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Expand file tree
/
Copy pathroles.go
More file actions
191 lines (173 loc) · 6.87 KB
/
roles.go
File metadata and controls
191 lines (173 loc) · 6.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
package codersdk
import (
"context"
"encoding/json"
"fmt"
"net/http"
"github.com/google/uuid"
)
// SlimRole omits permission information from a role.
// At present, this is because our apis do not return permission information,
// and it would require extra db calls to fetch this information. The UI does
// not need it, so most api calls will use this structure that omits information.
type SlimRole struct {
Name string `json:"name"`
DisplayName string `json:"display_name"`
OrganizationID string `json:"organization_id,omitempty"`
}
func (s SlimRole) String() string {
if s.DisplayName != "" {
return s.DisplayName
}
return s.Name
}
// UniqueName concatenates the organization ID to create a globally unique
// string name for the role.
func (s SlimRole) UniqueName() string {
if s.OrganizationID != "" {
return s.Name + ":" + s.OrganizationID
}
return s.Name
}
type AssignableRoles struct {
Role `table:"r,recursive_inline"`
Assignable bool `json:"assignable" table:"assignable"`
// BuiltIn roles are immutable
BuiltIn bool `json:"built_in" table:"built_in"`
}
// Permission is the format passed into the rego.
type Permission struct {
// Negate makes this a negative permission
Negate bool `json:"negate"`
ResourceType RBACResource `json:"resource_type"`
Action RBACAction `json:"action"`
}
// Role is a longer form of SlimRole that includes permissions details.
type Role struct {
Name string `json:"name" table:"name,default_sort" validate:"username"`
OrganizationID string `json:"organization_id,omitempty" table:"organization id" format:"uuid"`
DisplayName string `json:"display_name" table:"display name"`
SitePermissions []Permission `json:"site_permissions" table:"site permissions"`
UserPermissions []Permission `json:"user_permissions" table:"user permissions"`
// OrganizationPermissions are specific for the organization in the field 'OrganizationID' above.
OrganizationPermissions []Permission `json:"organization_permissions" table:"organization permissions"`
// OrganizationMemberPermissions are specific for the organization in the field 'OrganizationID' above.
OrganizationMemberPermissions []Permission `json:"organization_member_permissions" table:"organization member permissions"`
}
// CustomRoleRequest is used to edit custom roles.
type CustomRoleRequest struct {
Name string `json:"name" table:"name,default_sort" validate:"username"`
DisplayName string `json:"display_name" table:"display name"`
SitePermissions []Permission `json:"site_permissions" table:"site permissions"`
UserPermissions []Permission `json:"user_permissions" table:"user permissions"`
// OrganizationPermissions are specific to the organization the role belongs to.
OrganizationPermissions []Permission `json:"organization_permissions" table:"organization permissions"`
// OrganizationMemberPermissions are specific to the organization the role belongs to.
OrganizationMemberPermissions []Permission `json:"organization_member_permissions" table:"organization member permissions"`
}
// FullName returns the role name scoped to the organization ID. This is useful if
// printing a set of roles from different scopes, as duplicated names across multiple
// scopes will become unique.
// In practice, this is primarily used in testing.
func (r Role) FullName() string {
if r.OrganizationID == "" {
return r.Name
}
return r.Name + ":" + r.OrganizationID
}
// CreateOrganizationRole will create a custom organization role
func (c *Client) CreateOrganizationRole(ctx context.Context, role Role) (Role, error) {
req := CustomRoleRequest{
Name: role.Name,
DisplayName: role.DisplayName,
SitePermissions: role.SitePermissions,
UserPermissions: role.UserPermissions,
OrganizationPermissions: role.OrganizationPermissions,
OrganizationMemberPermissions: role.OrganizationMemberPermissions,
}
res, err := c.Request(ctx, http.MethodPost,
fmt.Sprintf("/api/v2/organizations/%s/members/roles", role.OrganizationID), req)
if err != nil {
return Role{}, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return Role{}, ReadBodyAsError(res)
}
var r Role
return r, json.NewDecoder(res.Body).Decode(&r)
}
// UpdateOrganizationRole will update an existing custom organization role
func (c *Client) UpdateOrganizationRole(ctx context.Context, role Role) (Role, error) {
req := CustomRoleRequest{
Name: role.Name,
DisplayName: role.DisplayName,
SitePermissions: role.SitePermissions,
UserPermissions: role.UserPermissions,
OrganizationPermissions: role.OrganizationPermissions,
OrganizationMemberPermissions: role.OrganizationMemberPermissions,
}
res, err := c.Request(ctx, http.MethodPut,
fmt.Sprintf("/api/v2/organizations/%s/members/roles", role.OrganizationID), req)
if err != nil {
return Role{}, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return Role{}, ReadBodyAsError(res)
}
var r Role
return r, json.NewDecoder(res.Body).Decode(&r)
}
// DeleteOrganizationRole will delete a custom organization role
func (c *Client) DeleteOrganizationRole(ctx context.Context, organizationID uuid.UUID, roleName string) error {
res, err := c.Request(ctx, http.MethodDelete,
fmt.Sprintf("/api/v2/organizations/%s/members/roles/%s", organizationID.String(), roleName), nil)
if err != nil {
return err
}
defer res.Body.Close()
if res.StatusCode != http.StatusNoContent {
return ReadBodyAsError(res)
}
return nil
}
// ListSiteRoles lists all assignable site wide roles.
func (c *Client) ListSiteRoles(ctx context.Context) ([]AssignableRoles, error) {
res, err := c.Request(ctx, http.MethodGet, "/api/v2/users/roles", nil)
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return nil, ReadBodyAsError(res)
}
var roles []AssignableRoles
return roles, json.NewDecoder(res.Body).Decode(&roles)
}
// ListOrganizationRoles lists all assignable roles for a given organization.
func (c *Client) ListOrganizationRoles(ctx context.Context, org uuid.UUID) ([]AssignableRoles, error) {
res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/organizations/%s/members/roles", org.String()), nil)
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return nil, ReadBodyAsError(res)
}
var roles []AssignableRoles
return roles, json.NewDecoder(res.Body).Decode(&roles)
}
// CreatePermissions is a helper function to quickly build permissions.
func CreatePermissions(mapping map[RBACResource][]RBACAction) []Permission {
perms := make([]Permission, 0)
for t, actions := range mapping {
for _, action := range actions {
perms = append(perms, Permission{
ResourceType: t,
Action: action,
})
}
}
return perms
}