-
Notifications
You must be signed in to change notification settings - Fork 692
/
members.go
135 lines (114 loc) · 4.11 KB
/
members.go
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
package coderd
import (
"context"
"net/http"
"github.com/google/uuid"
"golang.org/x/xerrors"
"github.com/coder/coder/coderd/rbac"
"github.com/coder/coder/coderd/database"
"github.com/coder/coder/coderd/httpapi"
"github.com/coder/coder/coderd/httpmw"
"github.com/coder/coder/codersdk"
)
// @Summary Assign role to organization member
// @ID assign-role-to-organization-member
// @Security CoderSessionToken
// @Accept json
// @Produce json
// @Tags Members
// @Param organization path string true "Organization ID"
// @Param user path string true "User ID, name, or me"
// @Param request body codersdk.UpdateRoles true "Update roles request"
// @Success 200 {object} codersdk.OrganizationMember
// @Router /organizations/{organization}/members/{user}/roles [put]
func (api *API) putMemberRoles(rw http.ResponseWriter, r *http.Request) {
var (
ctx = r.Context()
user = httpmw.UserParam(r)
organization = httpmw.OrganizationParam(r)
member = httpmw.OrganizationMemberParam(r)
apiKey = httpmw.APIKey(r)
actorRoles = httpmw.UserAuthorization(r)
)
if apiKey.UserID == member.UserID {
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
Message: "You cannot change your own organization roles.",
})
return
}
var params codersdk.UpdateRoles
if !httpapi.Read(ctx, rw, r, ¶ms) {
return
}
// The org-member role is always implied.
impliedTypes := append(params.Roles, rbac.RoleOrgMember(organization.ID))
added, removed := rbac.ChangeRoleSet(member.Roles, impliedTypes)
// Assigning a role requires the create permission.
if len(added) > 0 && !api.Authorize(r, rbac.ActionCreate, rbac.ResourceOrgRoleAssignment.InOrg(organization.ID)) {
httpapi.ResourceNotFound(rw)
return
}
// Removing a role requires the delete permission.
if len(removed) > 0 && !api.Authorize(r, rbac.ActionDelete, rbac.ResourceOrgRoleAssignment.InOrg(organization.ID)) {
httpapi.ResourceNotFound(rw)
return
}
// Just treat adding & removing as "assigning" for now.
for _, roleName := range append(added, removed...) {
if !rbac.CanAssignRole(actorRoles.Actor.Roles, roleName) {
httpapi.ResourceNotFound(rw)
return
}
}
updatedUser, err := api.updateOrganizationMemberRoles(ctx, database.UpdateMemberRolesParams{
GrantedRoles: params.Roles,
UserID: user.ID,
OrgID: organization.ID,
})
if err != nil {
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
Message: err.Error(),
})
return
}
httpapi.Write(ctx, rw, http.StatusOK, convertOrganizationMember(updatedUser))
}
func (api *API) updateOrganizationMemberRoles(ctx context.Context, args database.UpdateMemberRolesParams) (database.OrganizationMember, error) {
// Enforce only site wide roles
for _, r := range args.GrantedRoles {
// Must be an org role for the org in the args
orgID, ok := rbac.IsOrgRole(r)
if !ok {
return database.OrganizationMember{}, xerrors.Errorf("must only update organization roles")
}
roleOrg, err := uuid.Parse(orgID)
if err != nil {
return database.OrganizationMember{}, xerrors.Errorf("Role must have proper UUIDs for organization, %q does not", r)
}
if roleOrg != args.OrgID {
return database.OrganizationMember{}, xerrors.Errorf("Must only pass roles for org %q", args.OrgID.String())
}
if _, err := rbac.RoleByName(r); err != nil {
return database.OrganizationMember{}, xerrors.Errorf("%q is not a supported role", r)
}
}
updatedUser, err := api.Database.UpdateMemberRoles(ctx, args)
if err != nil {
return database.OrganizationMember{}, xerrors.Errorf("Update site roles: %w", err)
}
return updatedUser, nil
}
func convertOrganizationMember(mem database.OrganizationMember) codersdk.OrganizationMember {
convertedMember := codersdk.OrganizationMember{
UserID: mem.UserID,
OrganizationID: mem.OrganizationID,
CreatedAt: mem.CreatedAt,
UpdatedAt: mem.UpdatedAt,
Roles: make([]codersdk.Role, 0, len(mem.Roles)),
}
for _, roleName := range mem.Roles {
rbacRole, _ := rbac.RoleByName(roleName)
convertedMember.Roles = append(convertedMember.Roles, convertRole(rbacRole))
}
return convertedMember
}