11package middlewares
22
33import (
4- "app/base/rbac"
54 "app/base/utils"
65 "context"
76 "fmt"
87 "io"
98 "net/http"
109 "strings"
1110
12- "github.com/bytedance/sonic"
1311 "github.com/gin-gonic/gin"
1412 "github.com/pkg/errors"
1513 "github.com/redhatinsights/platform-go-middlewares/identity"
16- log "github.com/sirupsen/logrus"
1714 "google.golang.org/grpc"
1815
1916 "github.com/project-kessel/kessel-sdk-go/kessel/auth"
2017 kesselv2 "github.com/project-kessel/kessel-sdk-go/kessel/inventory/v1beta2"
2118)
2219
23- var granularPermissions = map [string ]string {
24- "TemplateSystemsUpdateHandler" : "patch_template_edit" ,
25- "TemplateSystemsDeleteHandler" : "patch_template_edit" ,
26- "SystemDeleteHandler" : "patch_system_edit" ,
27- }
28-
2920var credentials = auth .NewOAuth2ClientCredentials (
3021 utils .CoreCfg .KesselAuthClientID ,
3122 utils .CoreCfg .KesselAuthClientSecret ,
@@ -72,102 +63,30 @@ func processWorkspaces(workspaces []*kesselv2.StreamedListObjectsResponse) (map[
7263 return map [string ]string {utils .KeyGrouped : fmt .Sprintf ("{%s}" , strings .Join (groups , "," ))}, nil
7364}
7465
75- func getToken (ctx context.Context ) (string , error ) {
76- tokenReqCtx , tokenCtxCancel := context .WithCancel (ctx )
77- defer tokenCtxCancel ()
78- res , err := credentials .GetToken (tokenReqCtx , auth.GetTokenOptions {})
79- if err != nil {
80- return "" , err
81- }
82- return res .AccessToken , nil
83- }
84-
85- func getDefaultWorkspaceID (ctx context.Context , xrhid * identity.XRHID ) (string , error ) {
86- workspaceReqCtx , workspaceCtxCancel := context .WithCancel (ctx )
87- defer workspaceCtxCancel ()
88-
89- req , err := http .NewRequestWithContext (
90- workspaceReqCtx , http .MethodGet , utils .CoreCfg .RbacURL + "/v2/workspaces/?type=default" , nil )
91- if err != nil {
92- return "" , errors .Wrap (err , "Failed to create a request for default workspaceID" )
93- }
94- req .Header .Add ("x-rh-rbac-org-id" , xrhid .Identity .OrgID )
95-
96- if utils .CoreCfg .KesselAuthEnabled {
97- token , err := getToken (workspaceReqCtx )
98- if err != nil {
99- return "" , errors .Wrap (err , "Request for RBAC token failed" )
100- }
101- req .Header .Add ("authorization" , fmt .Sprintf ("Bearer %s" , token ))
102- }
103-
104- httpRes , err := utils .CallAPI (& http.Client {}, req , log .IsLevelEnabled (log .TraceLevel ))
105- if err != nil {
106- if httpRes != nil && httpRes .Body != nil {
107- httpRes .Body .Close ()
108- }
109- return "" , errors .Wrap (err , "Request failed" )
110- }
111-
112- var res rbac.DefaultWorkspaceResponse
113- err = sonic .ConfigDefault .NewDecoder (httpRes .Body ).Decode (& res )
114- if err != nil && err != io .EOF {
115- return "" , errors .Wrap (err , "Response body reading failed" )
66+ func buildPermission (c * gin.Context ) string {
67+ permission := "patch_system_"
68+ nameSplit := strings .Split (c .HandlerName (), "." )
69+ handlerName := nameSplit [len (nameSplit )- 1 ]
70+ if strings .HasPrefix (handlerName , "Template" ) {
71+ permission = "patch_template_"
11672 }
11773
118- if len (res .Data ) != 1 {
119- return "" , errors .New ("RBAC returned an unexpected number of default workspaces" )
74+ switch c .Request .Method {
75+ case http .MethodGet , http .MethodPost :
76+ permission += "view"
77+ case http .MethodPatch , http .MethodPut , http .MethodDelete :
78+ permission += "edit"
12079 }
12180
122- return res . Data [ 0 ]. ID , nil
81+ return permission
12382}
12483
125- func useCheckForUpdate (
84+ func useStreamedListObjects (
12685 c * gin.Context , client kesselv2.KesselInventoryServiceClient , xrhid * identity.XRHID , permission string ,
127- ) error {
128- checkReqCtx , checkCtxCancel := context .WithCancel (c )
129- defer checkCtxCancel ()
130-
131- workspaceID , err := getDefaultWorkspaceID (checkReqCtx , xrhid )
132- if err != nil {
133- return errors .Wrap (err , "could not get default workspaceID" )
134- }
135-
136- res , err := client .CheckForUpdate (checkReqCtx , & kesselv2.CheckForUpdateRequest {
137- Object : & kesselv2.ResourceReference {
138- ResourceType : "workspace" ,
139- ResourceId : workspaceID ,
140- Reporter : & kesselv2.ReporterReference {
141- Type : "rbac" ,
142- },
143- },
144- Relation : permission ,
145- Subject : buildSubject (xrhid ),
146- })
147- if err != nil {
148- return errors .Wrap (err , "failed to communicate with Kessel" )
149- }
150-
151- if res .Allowed != kesselv2 .Allowed_ALLOWED_TRUE {
152- c .AbortWithStatusJSON (http .StatusUnauthorized , utils.ErrorResponse {
153- Error : "Missing permission" , // does not have granular permission
154- })
155- }
156- return nil
157- }
158-
159- func useStreamedListObjects (c * gin.Context , client kesselv2.KesselInventoryServiceClient , xrhid * identity.XRHID ) error {
86+ ) ([]* kesselv2.StreamedListObjectsResponse , error ) {
16087 sloReqContext , sloContextCancel := context .WithCancel (c )
16188 defer sloContextCancel ()
16289
163- var permission string
164- switch c .Request .Method {
165- case http .MethodGet , http .MethodPost :
166- permission = "patch_all_view"
167- case http .MethodPut , http .MethodDelete :
168- permission = "patch_all_edit"
169- }
170-
17190 resourceType := "rbac"
17291 stream , err := client .StreamedListObjects (sloReqContext , & kesselv2.StreamedListObjectsRequest {
17392 ObjectType : & kesselv2.RepresentationType {
@@ -178,26 +97,18 @@ func useStreamedListObjects(c *gin.Context, client kesselv2.KesselInventoryServi
17897 Subject : buildSubject (xrhid ),
17998 })
18099 if err != nil {
181- return errors .Wrap (err , "failed to establish a gRPC stream with Kessel" )
100+ return nil , errors .Wrap (err , "failed to establish a gRPC stream with Kessel" )
182101 }
183102
184103 workspaces := make ([]* kesselv2.StreamedListObjectsResponse , 0 )
185104 for res , err := stream .Recv (); err != io .EOF ; res , err = stream .Recv () {
186105 if err != nil {
187- return errors .Wrap (err , "failed to receive all from Kessel" )
106+ return nil , errors .Wrap (err , "failed to receive all from Kessel" )
188107 }
189108 workspaces = append (workspaces , res )
190109 }
191110
192- inventoryGroups , err := processWorkspaces (workspaces )
193- if err != nil {
194- utils .LogError ("err" , err .Error (), "processWorkspaces" )
195- c .AbortWithStatusJSON (http .StatusUnauthorized , utils.ErrorResponse {
196- Error : "You don't have access to this application" ,
197- })
198- }
199- c .Set (utils .KeyInventoryGroups , inventoryGroups )
200- return nil
111+ return workspaces , nil
201112}
202113
203114func hasPermissionKessel (c * gin.Context ) {
@@ -216,24 +127,19 @@ func hasPermissionKessel(c *gin.Context) {
216127 c .AbortWithStatusJSON (http .StatusUnauthorized , utils.ErrorResponse {Error : "Invalid x-rh-identity header" })
217128 }
218129
219- // Require granular permission if set for handler
220- nameSplit := strings .Split (c .HandlerName (), "." )
221- handlerName := nameSplit [len (nameSplit )- 1 ]
222- if permission , has := granularPermissions [handlerName ]; has {
223- err = useCheckForUpdate (c , client , xrhid , permission )
224- if err != nil {
225- utils .LogError ("err" , err .Error (), "useCheckForUpdate failed" )
226- c .AbortWithStatus (http .StatusInternalServerError )
227- }
228- return
229- }
230-
231- // Require method-derived permission otherwise
232- err = useStreamedListObjects (c , client , xrhid )
130+ permission := buildPermission (c )
131+ workspaces , err := useStreamedListObjects (c , client , xrhid , permission )
233132 if err != nil {
234133 utils .LogError ("err" , err .Error (), "useStreamedListObjects failed" )
235134 c .AbortWithStatus (http .StatusInternalServerError )
236135 }
136+
137+ inventoryGroups , err := processWorkspaces (workspaces )
138+ if err != nil {
139+ utils .LogError ("err" , err .Error (), "processWorkspaces" )
140+ c .AbortWithStatusJSON (http .StatusUnauthorized , utils.ErrorResponse {Error : "Missing permission" })
141+ }
142+ c .Set (utils .KeyInventoryGroups , inventoryGroups )
237143}
238144
239145func Kessel () gin.HandlerFunc {
0 commit comments