-
Notifications
You must be signed in to change notification settings - Fork 14
/
permissions.go
115 lines (96 loc) · 3.14 KB
/
permissions.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
package accesscontrol
import (
"context"
"net/http"
"github.com/hashicorp/hcl/v2"
"github.com/avenga/couper/config/request"
"github.com/avenga/couper/errors"
"github.com/avenga/couper/eval"
"github.com/avenga/couper/handler/middleware"
"github.com/avenga/couper/internal/seetie"
)
type requiredPermissions struct {
permission string
permissions map[string]string // permission per method
}
func newRequiredPermissions(permission string, permissionMap map[string]string) requiredPermissions {
rp := requiredPermissions{}
if permissionMap == nil {
rp.permission = permission
return rp
}
rp.setPermissionMap(permissionMap)
return rp
}
func (r *requiredPermissions) setPermissionMap(permissionMap map[string]string) {
r.permissions = make(map[string]string)
if otherPermission, otherMethodExists := permissionMap["*"]; otherMethodExists {
for _, method := range middleware.DefaultEndpointAllowedMethods {
r.permissions[method] = otherPermission
}
}
for method, permission := range permissionMap {
if method == "*" {
continue
}
r.permissions[method] = permission
}
}
func (r *requiredPermissions) getPermission(method string) (string, error) {
if r.permissions == nil {
return r.permission, nil
}
permission, exists := r.permissions[method]
if !exists {
return "", errors.MethodNotAllowed.Messagef("method %s not allowed by beta_required_permission", method)
}
return permission, nil
}
var _ AccessControl = &PermissionsControl{}
type PermissionsControl struct {
permissionExpr hcl.Expression
}
func NewPermissionsControl(permissionExpr hcl.Expression) *PermissionsControl {
return &PermissionsControl{permissionExpr: permissionExpr}
}
// Validate validates the granted permissions provided by access controls against the required permission.
func (p *PermissionsControl) Validate(req *http.Request) error {
if p.permissionExpr == nil {
return nil
}
permissionVal, err := eval.Value(eval.ContextFromRequest(req).HCLContext(), p.permissionExpr)
permission, permissionMap, err := seetie.ValueToPermission(permissionVal)
if err != nil {
return errors.Evaluation.With(err)
}
rp := newRequiredPermissions(permission, permissionMap)
requiredPermission, err := rp.getPermission(req.Method)
if err != nil {
return err
}
if requiredPermission == "" {
return nil
}
ctx := req.Context()
ctx = context.WithValue(ctx, request.BetaRequiredPermission, requiredPermission)
*req = *req.WithContext(ctx)
evalCtx := eval.ContextFromRequest(req)
*req = *req.WithContext(evalCtx.WithClientRequest(req))
grantedPermission, ok := ctx.Value(request.BetaGrantedPermissions).([]string)
if !ok {
return errors.BetaInsufficientPermissions.Messagef("no permissions granted")
}
if !hasGrantedPermission(grantedPermission, requiredPermission) {
return errors.BetaInsufficientPermissions.Messagef("required permission %q not granted", requiredPermission)
}
return nil
}
// hasGrantedPermission checks whether a given permission is in the granted permissions
func hasGrantedPermission(grantedPermissions []string, permission string) bool {
for _, gp := range grantedPermissions {
if gp == permission {
return true
}
}
return false
}