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
|
package authz
import (
"context"
"net/http"
"path/filepath"
v1 "github.com/authzed/authzed-go/proto/authzed/api/v1"
authzed "github.com/authzed/authzed-go/v1"
core "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
auth "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3"
types "github.com/envoyproxy/go-control-plane/envoy/type/v3"
"github.com/xlgmokha/x/pkg/log"
"github.com/xlgmokha/x/pkg/mapper"
"github.com/xlgmokha/x/pkg/x"
"gitlab.com/gitlab-org/software-supply-chain-security/authorization/authzd.git/pkg/pls"
status "google.golang.org/genproto/googleapis/rpc/status"
"google.golang.org/grpc/codes"
)
var StaticAssets []string = []string{".png", ".css", ".html", ".js", ".ico"}
type CheckService struct {
client *authzed.Client
auth.UnimplementedAuthorizationServer
}
func NewCheckService(client *authzed.Client) auth.AuthorizationServer {
return &CheckService{
client: client,
}
}
func (svc *CheckService) Check(ctx context.Context, request *auth.CheckRequest) (*auth.CheckResponse, error) {
if svc.isAuthorized(ctx, request) {
return svc.OK(ctx), nil
}
return svc.Denied(ctx), nil
}
func (svc *CheckService) isAuthorized(ctx context.Context, r *auth.CheckRequest) bool {
if !svc.validRequest(ctx, r) {
return false
}
log.WithFields(ctx, mapper.MapFrom[*auth.CheckRequest, log.Fields](r))
if svc.isStaticAsset(ctx, r) {
return true
}
if x.IsZero(svc.client) {
return false
}
request := mapper.MapFrom[*auth.CheckRequest, *v1.CheckPermissionRequest](r)
response, err := svc.client.CheckPermission(ctx, request)
log.WithFields(ctx, log.Fields{
"spice_request": request,
"spice_response": response,
})
if err != nil {
pls.LogError(ctx, err)
return false
}
return response.Permissionship == v1.CheckPermissionResponse_PERMISSIONSHIP_HAS_PERMISSION
}
func (svc *CheckService) isStaticAsset(ctx context.Context, r *auth.CheckRequest) bool {
if r.Attributes.Request.Http.Method != http.MethodGet {
return false
}
extension := filepath.Ext(r.Attributes.Request.Http.Path)
return x.Contains(StaticAssets, func(item string) bool {
return item == extension
})
}
func (svc *CheckService) validRequest(ctx context.Context, r *auth.CheckRequest) bool {
return x.IsPresent(r) &&
x.IsPresent(r.Attributes) &&
x.IsPresent(r.Attributes.Request) &&
x.IsPresent(r.Attributes.Request.Http)
}
func (svc *CheckService) OK(ctx context.Context) *auth.CheckResponse {
log.WithFields(ctx, log.Fields{"authorized": true})
return &auth.CheckResponse{
Status: &status.Status{
Code: int32(codes.OK),
},
HttpResponse: &auth.CheckResponse_OkResponse{
OkResponse: &auth.OkHttpResponse{
Headers: []*core.HeaderValueOption{},
HeadersToRemove: []string{},
ResponseHeadersToAdd: []*core.HeaderValueOption{},
},
},
}
}
func (svc *CheckService) Denied(ctx context.Context) *auth.CheckResponse {
log.WithFields(ctx, log.Fields{"authorized": false})
return &auth.CheckResponse{
Status: &status.Status{
Code: int32(codes.PermissionDenied),
},
HttpResponse: &auth.CheckResponse_DeniedResponse{
DeniedResponse: &auth.DeniedHttpResponse{
Status: &types.HttpStatus{
Code: types.StatusCode_Unauthorized,
},
Headers: []*core.HeaderValueOption{},
},
},
}
}
|