Skip to content

Commit 40b0b18

Browse files
committed
gateway: initial rbac handling
For every action check if the current user as a role that con do such action.
1 parent 0886349 commit 40b0b18

File tree

9 files changed

+522
-349
lines changed

9 files changed

+522
-349
lines changed

internal/services/gateway/action/auth.go

Lines changed: 199 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -48,131 +48,143 @@ func (h *ActionHandler) IsUserLoggedOrAdmin(ctx context.Context) bool {
4848
return h.IsUserLogged(ctx) || h.IsUserAdmin(ctx)
4949
}
5050

51-
func (h *ActionHandler) IsOrgOwner(ctx context.Context, orgID string) (bool, error) {
52-
isAdmin := h.IsUserAdmin(ctx)
53-
if isAdmin {
54-
return true, nil
55-
}
51+
func (h *ActionHandler) userActionsForUser(ctx context.Context, userRef string) ([]cstypes.ActionType, error) {
52+
actions := []cstypes.ActionType{}
5653

5754
userID := h.CurrentUserID(ctx)
5855
if userID == "" {
59-
return false, nil
56+
return actions, nil
57+
}
58+
59+
// By default any logged user can get an user
60+
actions = append(actions, cstypes.ActionTypeGetUser)
61+
62+
// no existing user
63+
if userRef == "" {
64+
return actions, nil
6065
}
6166

62-
userOrgs, resp, err := h.configstoreClient.GetUserOrgs(ctx, userID)
67+
user, resp, err := h.configstoreClient.GetUser(ctx, userRef)
6368
if err != nil {
64-
return false, errors.Errorf("failed to get user orgs: %w", ErrFromRemote(resp, err))
69+
return nil, ErrFromRemote(resp, err)
6570
}
6671

67-
for _, userOrg := range userOrgs {
68-
if userOrg.Organization.ID != orgID {
69-
continue
70-
}
71-
if userOrg.Role == cstypes.OrgMemberRoleOwner {
72-
return true, nil
73-
}
72+
ownerActions, err := h.userActionsForOwner(ctx, cstypes.ConfigTypeUser, user.ID)
73+
if err != nil {
74+
return nil, err
7475
}
76+
actions = append(actions, ownerActions...)
7577

76-
return false, nil
78+
return actions, nil
7779
}
7880

79-
func (h *ActionHandler) IsProjectOwner(ctx context.Context, ownerType cstypes.ConfigType, ownerID string) (bool, error) {
80-
isAdmin := h.IsUserAdmin(ctx)
81-
if isAdmin {
82-
return true, nil
83-
}
81+
func (h *ActionHandler) userActionsForOrg(ctx context.Context, orgRef string) ([]cstypes.ActionType, error) {
82+
actions := []cstypes.ActionType{}
8483

8584
userID := h.CurrentUserID(ctx)
8685
if userID == "" {
87-
return false, nil
86+
return actions, nil
8887
}
8988

90-
if ownerType == cstypes.ConfigTypeUser {
91-
if userID == ownerID {
92-
return true, nil
93-
}
89+
// By default any logged user can create an org
90+
actions = append(actions, cstypes.ActionTypeCreateOrg)
91+
92+
// no existing org
93+
if orgRef == "" {
94+
return actions, nil
9495
}
9596

96-
if ownerType == cstypes.ConfigTypeOrg {
97-
userOrgs, resp, err := h.configstoreClient.GetUserOrgs(ctx, userID)
98-
if err != nil {
99-
return false, errors.Errorf("failed to get user orgs: %w", ErrFromRemote(resp, err))
100-
}
97+
org, resp, err := h.configstoreClient.GetOrg(ctx, orgRef)
98+
if err != nil {
99+
return nil, ErrFromRemote(resp, err)
100+
}
101101

102-
for _, userOrg := range userOrgs {
103-
if userOrg.Organization.ID != ownerID {
104-
continue
105-
}
106-
if userOrg.Role == cstypes.OrgMemberRoleOwner {
107-
return true, nil
108-
}
109-
}
102+
if org.Visibility == cstypes.VisibilityPublic {
103+
actions = append(actions, cstypes.OrgMemberActions...)
110104
}
111105

112-
return false, nil
106+
ownerRoles, err := h.userActionsForOwner(ctx, cstypes.ConfigTypeOrg, org.ID)
107+
if err != nil {
108+
return nil, err
109+
}
110+
actions = append(actions, ownerRoles...)
111+
112+
return actions, nil
113113
}
114114

115-
func (h *ActionHandler) IsProjectMember(ctx context.Context, ownerType cstypes.ConfigType, ownerID string) (bool, error) {
116-
isAdmin := h.IsUserAdmin(ctx)
117-
if isAdmin {
118-
return true, nil
119-
}
115+
func (h *ActionHandler) userActionsForProjectGroup(ctx context.Context, projectGroupRef string) ([]cstypes.ActionType, error) {
116+
actions := []cstypes.ActionType{}
120117

121118
userID := h.CurrentUserID(ctx)
122119
if userID == "" {
123-
return false, nil
120+
return actions, nil
124121
}
125122

126-
if ownerType == cstypes.ConfigTypeUser {
127-
if userID == ownerID {
128-
return true, nil
129-
}
123+
p, resp, err := h.configstoreClient.GetProjectGroup(ctx, projectGroupRef)
124+
if err != nil {
125+
return nil, ErrFromRemote(resp, err)
130126
}
131127

132-
if ownerType == cstypes.ConfigTypeOrg {
133-
userOrgs, resp, err := h.configstoreClient.GetUserOrgs(ctx, userID)
134-
if err != nil {
135-
return false, errors.Errorf("failed to get user orgs: %w", ErrFromRemote(resp, err))
136-
}
128+
if p.GlobalVisibility == cstypes.VisibilityPublic {
129+
actions = append(actions, cstypes.ProjectReadActions...)
130+
}
137131

138-
for _, userOrg := range userOrgs {
139-
if userOrg.Organization.ID != ownerID {
140-
continue
141-
}
142-
return true, nil
143-
}
132+
ownerRoles, err := h.userActionsForOwner(ctx, p.OwnerType, p.OwnerID)
133+
if err != nil {
134+
return nil, err
144135
}
136+
actions = append(actions, ownerRoles...)
145137

146-
return false, nil
138+
return actions, nil
147139
}
148140

149-
func (h *ActionHandler) IsVariableOwner(ctx context.Context, parentType cstypes.ConfigType, parentRef string) (bool, error) {
150-
var ownerType cstypes.ConfigType
151-
var ownerID string
141+
func (h *ActionHandler) userActionsForProject(ctx context.Context, projectRef string) ([]cstypes.ActionType, error) {
142+
actions := []cstypes.ActionType{}
143+
144+
userID := h.CurrentUserID(ctx)
145+
if userID == "" {
146+
return actions, nil
147+
}
148+
149+
p, resp, err := h.configstoreClient.GetProject(ctx, projectRef)
150+
if err != nil {
151+
return nil, ErrFromRemote(resp, err)
152+
}
153+
154+
if p.GlobalVisibility == cstypes.VisibilityPublic {
155+
actions = append(actions, cstypes.ProjectReadActions...)
156+
}
157+
ownerRoles, err := h.userActionsForOwner(ctx, p.OwnerType, p.OwnerID)
158+
if err != nil {
159+
return nil, err
160+
}
161+
actions = append(actions, ownerRoles...)
162+
163+
return actions, nil
164+
}
165+
166+
func (h *ActionHandler) userActionsForVariable(ctx context.Context, parentType cstypes.ConfigType, parentRef string) ([]cstypes.ActionType, error) {
152167
switch parentType {
153168
case cstypes.ConfigTypeProjectGroup:
154-
pg, resp, err := h.configstoreClient.GetProjectGroup(ctx, parentRef)
155-
if err != nil {
156-
return false, errors.Errorf("failed to get project group %q: %w", parentRef, ErrFromRemote(resp, err))
157-
}
158-
ownerType = pg.OwnerType
159-
ownerID = pg.OwnerID
169+
return h.userActionsForProjectGroup(ctx, parentRef)
160170
case cstypes.ConfigTypeProject:
161-
p, resp, err := h.configstoreClient.GetProject(ctx, parentRef)
162-
if err != nil {
163-
return false, errors.Errorf("failed to get project %q: %w", parentRef, ErrFromRemote(resp, err))
164-
}
165-
ownerType = p.OwnerType
166-
ownerID = p.OwnerID
171+
return h.userActionsForProject(ctx, parentRef)
172+
default:
173+
return nil, errors.Errorf("wrong parent type: %q", parentType)
167174
}
168-
169-
return h.IsProjectOwner(ctx, ownerType, ownerID)
170175
}
171176

172-
func (h *ActionHandler) CanGetRun(ctx context.Context, runGroup string) (bool, error) {
177+
func (h *ActionHandler) userActionsForRun(ctx context.Context, runGroup string) ([]cstypes.ActionType, error) {
178+
actions := []cstypes.ActionType{}
179+
180+
userID := h.CurrentUserID(ctx)
181+
if userID == "" {
182+
return actions, nil
183+
}
184+
173185
groupType, groupID, err := common.GroupTypeIDFromRunGroup(runGroup)
174186
if err != nil {
175-
return false, err
187+
return nil, err
176188
}
177189

178190
var visibility cstypes.Visibility
@@ -182,59 +194,137 @@ func (h *ActionHandler) CanGetRun(ctx context.Context, runGroup string) (bool, e
182194
case common.GroupTypeProject:
183195
p, resp, err := h.configstoreClient.GetProject(ctx, groupID)
184196
if err != nil {
185-
return false, ErrFromRemote(resp, err)
197+
return nil, ErrFromRemote(resp, err)
186198
}
187199
ownerType = p.OwnerType
188200
ownerID = p.OwnerID
189201
visibility = p.GlobalVisibility
202+
190203
case common.GroupTypeUser:
191204
// user direct runs
192205
ownerType = cstypes.ConfigTypeUser
193206
ownerID = groupID
194207
visibility = cstypes.VisibilityPrivate
208+
default:
209+
return nil, errors.Errorf("wrong run group type: %q", runGroup)
195210
}
196211

197212
if visibility == cstypes.VisibilityPublic {
198-
return true, nil
213+
actions = append(actions, cstypes.ProjectReadActions...)
199214
}
200-
isProjectMember, err := h.IsProjectMember(ctx, ownerType, ownerID)
215+
ownerRoles, err := h.userActionsForOwner(ctx, ownerType, ownerID)
201216
if err != nil {
202-
return false, errors.Errorf("failed to determine ownership: %w", err)
217+
return nil, err
218+
}
219+
actions = append(actions, ownerRoles...)
220+
221+
return actions, nil
222+
}
223+
224+
func (h *ActionHandler) userActionsForOwner(ctx context.Context, ownerType cstypes.ConfigType, ownerID string) ([]cstypes.ActionType, error) {
225+
actions := []cstypes.ActionType{}
226+
227+
userID := h.CurrentUserID(ctx)
228+
if userID == "" {
229+
return actions, nil
203230
}
204-
if !isProjectMember {
205-
return false, nil
231+
232+
switch ownerType {
233+
case cstypes.ConfigTypeUser:
234+
if userID == ownerID {
235+
actions = append(actions, cstypes.UserOwnerActions...)
236+
}
237+
case cstypes.ConfigTypeOrg:
238+
userOrgs, resp, err := h.configstoreClient.GetUserOrgs(ctx, userID)
239+
if err != nil {
240+
return nil, errors.Errorf("failed to get user orgs: %w", ErrFromRemote(resp, err))
241+
}
242+
243+
for _, userOrg := range userOrgs {
244+
if userOrg.Organization.ID != ownerID {
245+
continue
246+
}
247+
if userOrg.Role == cstypes.OrgMemberRoleOwner {
248+
actions = append(actions, cstypes.OrgOwnerActions...)
249+
}
250+
if userOrg.Role == cstypes.OrgMemberRoleMember {
251+
actions = append(actions, cstypes.OrgMemberActions...)
252+
}
253+
}
206254
}
207-
return true, nil
255+
256+
return actions, nil
208257
}
209258

210-
func (h *ActionHandler) CanDoRunActions(ctx context.Context, runGroup string) (bool, error) {
211-
groupType, groupID, err := common.GroupTypeIDFromRunGroup(runGroup)
259+
func (h *ActionHandler) CanDoUserAction(ctx context.Context, action cstypes.ActionType, userRef string) (bool, error) {
260+
actions, err := h.userActionsForUser(ctx, userRef)
212261
if err != nil {
213262
return false, err
214263
}
215264

216-
var ownerType cstypes.ConfigType
217-
var ownerID string
218-
switch groupType {
219-
case common.GroupTypeProject:
220-
p, resp, err := h.configstoreClient.GetProject(ctx, groupID)
221-
if err != nil {
222-
return false, ErrFromRemote(resp, err)
223-
}
224-
ownerType = p.OwnerType
225-
ownerID = p.OwnerID
226-
case common.GroupTypeUser:
227-
// user direct runs
228-
ownerType = cstypes.ConfigTypeUser
229-
ownerID = groupID
265+
return h.CanDoAction(ctx, actions, action)
266+
}
267+
268+
func (h *ActionHandler) CanDoOrgAction(ctx context.Context, action cstypes.ActionType, orgRef string) (bool, error) {
269+
actions, err := h.userActionsForOrg(ctx, orgRef)
270+
if err != nil {
271+
return false, err
272+
}
273+
274+
return h.CanDoAction(ctx, actions, action)
275+
}
276+
277+
func (h *ActionHandler) CanDoProjectGroupAction(ctx context.Context, action cstypes.ActionType, projectGroupRef string) (bool, error) {
278+
actions, err := h.userActionsForProjectGroup(ctx, projectGroupRef)
279+
if err != nil {
280+
return false, err
230281
}
231282

232-
isProjectOwner, err := h.IsProjectOwner(ctx, ownerType, ownerID)
283+
return h.CanDoAction(ctx, actions, action)
284+
}
285+
286+
func (h *ActionHandler) CanDoProjectAction(ctx context.Context, action cstypes.ActionType, projectRef string) (bool, error) {
287+
actions, err := h.userActionsForProject(ctx, projectRef)
233288
if err != nil {
234-
return false, errors.Errorf("failed to determine ownership: %w", err)
289+
return false, err
235290
}
236-
if !isProjectOwner {
237-
return false, nil
291+
292+
return h.CanDoAction(ctx, actions, action)
293+
}
294+
295+
func (h *ActionHandler) CanDoVariableAction(ctx context.Context, action cstypes.ActionType, parentType cstypes.ConfigType, parentRef string) (bool, error) {
296+
actions, err := h.userActionsForVariable(ctx, parentType, parentRef)
297+
if err != nil {
298+
return false, err
238299
}
239-
return true, nil
300+
301+
return h.CanDoAction(ctx, actions, action)
302+
}
303+
func (h *ActionHandler) CanDoSecretAction(ctx context.Context, action cstypes.ActionType, parentType cstypes.ConfigType, parentRef string) (bool, error) {
304+
return h.CanDoVariableAction(ctx, action, parentType, parentRef)
305+
}
306+
307+
func (h *ActionHandler) CanDoRunAction(ctx context.Context, action cstypes.ActionType, runGroup string) (bool, error) {
308+
actions, err := h.userActionsForRun(ctx, runGroup)
309+
if err != nil {
310+
return false, err
311+
}
312+
313+
return h.CanDoAction(ctx, actions, action)
314+
}
315+
316+
func (h *ActionHandler) CanDoAction(ctx context.Context, actions []cstypes.ActionType, action cstypes.ActionType) (bool, error) {
317+
isAdmin := h.IsUserAdmin(ctx)
318+
if isAdmin {
319+
actions = append(actions, cstypes.AdminActions...)
320+
}
321+
322+
for _, a := range actions {
323+
if a != action {
324+
continue
325+
}
326+
return true, nil
327+
}
328+
329+
return false, nil
240330
}

0 commit comments

Comments
 (0)