-
Notifications
You must be signed in to change notification settings - Fork 361
/
arn.go
111 lines (99 loc) · 2.42 KB
/
arn.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
package auth
import (
"strings"
"github.com/treeverse/lakefs/pkg/auth/wildcard"
"github.com/treeverse/lakefs/pkg/permissions"
)
type Arn struct {
Partition string
Service string
Region string
AccountID string
ResourceID string
}
const (
fieldIndexArn = iota
fieldIndexPartition
fieldIndexService
fieldIndexRegion
fieldIndexAccount
fieldIndexResource
numFieldIndexes
)
func arnParseField(arn *Arn, field string, fieldIndex int) error {
switch fieldIndex {
case fieldIndexArn:
if field != "arn" {
return ErrInvalidArn
}
case fieldIndexPartition:
if field != "lakefs" {
return ErrInvalidArn
}
arn.Partition = field
case fieldIndexService:
if len(field) < 1 {
return ErrInvalidArn
}
arn.Service = field
case fieldIndexRegion:
arn.Region = field
case fieldIndexAccount:
arn.AccountID = field
case fieldIndexResource:
if len(field) < 1 {
return ErrInvalidArn
}
arn.ResourceID = field
}
return nil
}
func ParseARN(arnString string) (*Arn, error) {
// BUG(ozkatz): This parser does not handle resource types. Handling resource types is
// subtle: they may be separated from resource IDs by a colon OR by a slash. For an
// example of a resource type, see ECS[1] (uses only slash separators). That colons
// are an acceptable separator appears in [2], so a workaround to this limitation is
// to use a slash.
//
// [1] https://docs.aws.amazon.com/AmazonECS/latest/developerguide/security_iam_service-with-iam.html#security_iam_service-with-iam-id-based-policies-resources
// [2] https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#arns-syntax
parts := strings.SplitN(arnString, ":", numFieldIndexes)
if len(parts) < numFieldIndexes {
return nil, ErrInvalidArn
}
arn := &Arn{}
for currField, part := range parts {
err := arnParseField(arn, part, currField)
if err != nil {
return arn, err
}
}
return arn, nil
}
func ArnMatch(src, dst string) bool {
if src == permissions.All {
return true
}
source, err := ParseARN(src)
if err != nil {
return false
}
dest, err := ParseARN(dst)
if err != nil {
return false
}
if source.Service != dest.Service {
return false
}
if source.Partition != dest.Partition {
return false
}
if source.AccountID != dest.AccountID {
return false
}
// wildcards are allowed for resources only
if wildcard.Match(source.ResourceID, dest.ResourceID) {
return true
}
return false
}