Skip to content

Commit 60f5680

Browse files
adi6859iamayushm
andauthored
fix: chart group rbac issue (#5183)
* chart group rbac issue fixed * bulk rbac support added * issue fixed around bulk case * authreq added * comment updated --------- Co-authored-by: ayushmaheshwari <[email protected]> Co-authored-by: iamayushm <[email protected]>
1 parent 2af67f1 commit 60f5680

File tree

3 files changed

+128
-2
lines changed

3 files changed

+128
-2
lines changed

api/appStore/InstalledAppRestHandler.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
util3 "github.com/devtron-labs/devtron/pkg/appStore/util"
2929
"github.com/devtron-labs/devtron/pkg/bean"
3030
"net/http"
31+
"reflect"
3132
"strconv"
3233
"strings"
3334
"time"
@@ -363,6 +364,8 @@ func (handler *InstalledAppRestHandlerImpl) DeployBulk(w http.ResponseWriter, r
363364
common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), nil, http.StatusForbidden)
364365
return
365366
}
367+
charts, authRes := handler.checkForHelmDeployAuth(request, token)
368+
request.ChartGroupInstallChartRequest = charts
366369
//RBAC block ends here
367370

368371
visited := make(map[string]bool)
@@ -391,10 +394,116 @@ func (handler *InstalledAppRestHandlerImpl) DeployBulk(w http.ResponseWriter, r
391394
handler.Logger.Errorw("service err, DeployBulk", "err", err, "payload", request)
392395
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
393396
return
397+
} else {
398+
res = authRes
394399
}
395400
common.WriteJsonResp(w, err, res, http.StatusOK)
396401
}
397402

403+
func (handler *InstalledAppRestHandlerImpl) checkForHelmDeployAuth(request chartGroup.ChartGroupInstallRequest, token string) ([]*chartGroup.ChartGroupInstallChartRequest, *chartGroup.ChartGroupInstallAppRes) {
404+
//the value of this map is array of integer because the GetHelmObjectByProjectIdAndEnvId method may return "//" for error cases
405+
//so different environments may contain same object, to handle that we are using (map[string] []int)
406+
rbacObjectToEnvIdMap1 := make(map[string][]int)
407+
rbacObjectToEnvIdMap2 := make(map[string][]int)
408+
409+
rbacObjectArray1 := make([]string, 0)
410+
rbacObjectArray2 := make([]string, 0)
411+
412+
envIdToChartGroupInstallChartRequest := make(map[int][]*chartGroup.ChartGroupInstallChartRequest)
413+
414+
for _, chartGroupInstall := range request.ChartGroupInstallChartRequest {
415+
envIdToChartGroupInstallChartRequest[chartGroupInstall.EnvironmentId] = append(envIdToChartGroupInstallChartRequest[chartGroupInstall.EnvironmentId], chartGroupInstall)
416+
rbacObject1, rbacObject2 := handler.enforcerUtil.GetHelmObjectByProjectIdAndEnvId(request.ProjectId, chartGroupInstall.EnvironmentId)
417+
_, ok := rbacObjectToEnvIdMap1[rbacObject1]
418+
if !ok {
419+
rbacObjectToEnvIdMap1[rbacObject1] = make([]int, 0)
420+
}
421+
rbacObjectToEnvIdMap1[rbacObject1] = append(rbacObjectToEnvIdMap1[rbacObject1], chartGroupInstall.EnvironmentId)
422+
rbacObjectArray1 = append(rbacObjectArray1, rbacObject1)
423+
_, ok = rbacObjectToEnvIdMap2[rbacObject2]
424+
if !ok {
425+
rbacObjectToEnvIdMap2[rbacObject2] = make([]int, 0)
426+
}
427+
rbacObjectToEnvIdMap2[rbacObject2] = append(rbacObjectToEnvIdMap2[rbacObject2], chartGroupInstall.EnvironmentId)
428+
rbacObjectArray2 = append(rbacObjectArray2, rbacObject2)
429+
}
430+
resultObjectMap1 := handler.enforcer.EnforceInBatch(token, casbin.ResourceHelmApp, casbin.ActionCreate, rbacObjectArray1)
431+
resultObjectMap2 := handler.enforcer.EnforceInBatch(token, casbin.ResourceHelmApp, casbin.ActionCreate, rbacObjectArray2)
432+
433+
authorizedEnvIdSet := make(map[int]bool)
434+
435+
//O(n) time loop , at max we will only iterate through all the envs
436+
for obj, ok := range resultObjectMap1 {
437+
if ok {
438+
envIds := rbacObjectToEnvIdMap1[obj]
439+
for _, envId := range envIds {
440+
authorizedEnvIdSet[envId] = true
441+
}
442+
}
443+
}
444+
for obj, ok := range resultObjectMap2 {
445+
if ok {
446+
envIds := rbacObjectToEnvIdMap2[obj]
447+
for _, envId := range envIds {
448+
authorizedEnvIdSet[envId] = true
449+
}
450+
}
451+
}
452+
authorizedChartGroupInstallRequests := make([]*chartGroup.ChartGroupInstallChartRequest, 0)
453+
for envId, _ := range authorizedEnvIdSet {
454+
authorizedChartGroupInstall := envIdToChartGroupInstallChartRequest[envId]
455+
for _, authChartGroup := range authorizedChartGroupInstall {
456+
authorizedChartGroupInstallRequests = append(authorizedChartGroupInstallRequests, authChartGroup)
457+
}
458+
}
459+
unauthorizedChartGroupInstallRequests := make([]*chartGroup.ChartGroupInstallChartRequest, 0)
460+
461+
for _, req := range request.ChartGroupInstallChartRequest {
462+
isAuthorized := false
463+
for _, authReq := range authorizedChartGroupInstallRequests {
464+
if reflect.DeepEqual(req, authReq) {
465+
isAuthorized = true
466+
break
467+
}
468+
}
469+
if !isAuthorized {
470+
unauthorizedChartGroupInstallRequests = append(unauthorizedChartGroupInstallRequests, req)
471+
}
472+
}
473+
474+
// Create slices for ChartGroupInstallMetadata
475+
authorizedMetadata := make([]chartGroup.ChartGroupInstallMetadata, 0)
476+
unauthorizedMetadata := make([]chartGroup.ChartGroupInstallMetadata, 0)
477+
478+
for _, req := range authorizedChartGroupInstallRequests {
479+
metadata := handler.getChartGroupInstallMetadata(req, string(chartGroup.StatusSuccess), string(chartGroup.ReasonTriggered))
480+
authorizedMetadata = append(authorizedMetadata, metadata)
481+
}
482+
483+
for _, req := range unauthorizedChartGroupInstallRequests {
484+
metadata := handler.getChartGroupInstallMetadata(req, string(chartGroup.StatusFailed), string(chartGroup.ReasonNotAuthorize))
485+
unauthorizedMetadata = append(unauthorizedMetadata, metadata)
486+
}
487+
unauthorizeCount := len(unauthorizedChartGroupInstallRequests)
488+
totalCount := len(request.ChartGroupInstallChartRequest)
489+
// Combine all metadata into a single ChartGroupInstallAppRes
490+
chartGroupInstallAppRes := &chartGroup.ChartGroupInstallAppRes{
491+
ChartGroupInstallMetadata: append(authorizedMetadata, unauthorizedMetadata...),
492+
Summary: fmt.Sprintf(chartGroup.FAILED_TO_TRIGGER, unauthorizeCount, totalCount),
493+
}
494+
return authorizedChartGroupInstallRequests, chartGroupInstallAppRes
495+
}
496+
497+
func (handler *InstalledAppRestHandlerImpl) getChartGroupInstallMetadata(req *chartGroup.ChartGroupInstallChartRequest, triggerStatus string, reason string) chartGroup.ChartGroupInstallMetadata {
498+
metadata := chartGroup.ChartGroupInstallMetadata{
499+
AppName: req.AppName,
500+
EnvironmentId: req.EnvironmentId,
501+
TriggerStatus: triggerStatus,
502+
Reason: reason,
503+
}
504+
return metadata
505+
}
506+
398507
func (handler *InstalledAppRestHandlerImpl) CheckAppExists(w http.ResponseWriter, r *http.Request) {
399508
userId, err := handler.userAuthService.GetLoggedInUser(r)
400509
if userId == 0 || err != nil {

pkg/appStore/chartGroup/bean.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,23 @@ type ChartGroupInstallChartRequest struct {
3333
ReferenceValueKind string `json:"referenceValueKind, omitempty" validate:"oneof=DEFAULT TEMPLATE DEPLOYED"`
3434
ChartGroupEntryId int `json:"chartGroupEntryId"` //optional
3535
}
36-
36+
type ChartGroupInstallMetadata struct {
37+
AppName string `json:"appName"`
38+
EnvironmentId int `json:"environmentId"`
39+
TriggerStatus string `json:"triggerStatus"`
40+
Reason string `json:"reason"`
41+
}
3742
type ChartGroupInstallAppRes struct {
43+
ChartGroupInstallMetadata []ChartGroupInstallMetadata `json:"chartGroupInstallMetadata"`
44+
Summary string `json:"summary"`
3845
}
46+
type TriggerStatus string
47+
type Reason string
48+
49+
const FAILED_TO_TRIGGER = "%d/%d failed to trigger"
50+
const (
51+
StatusFailed TriggerStatus = "failed"
52+
StatusSuccess TriggerStatus = "success"
53+
ReasonNotAuthorize Reason = "not authorized"
54+
ReasonTriggered Reason = "triggered"
55+
)

wire_gen.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)