1package consul 2 3import ( 4 "github.com/hashicorp/consul/acl" 5 "github.com/hashicorp/consul/agent/structs" 6) 7 8type dirEntFilter struct { 9 authorizer acl.Authorizer 10 ent structs.DirEntries 11} 12 13func (d *dirEntFilter) Len() int { 14 return len(d.ent) 15} 16func (d *dirEntFilter) Filter(i int) bool { 17 var entCtx acl.AuthorizerContext 18 d.ent[i].FillAuthzContext(&entCtx) 19 20 return d.authorizer.KeyRead(d.ent[i].Key, &entCtx) != acl.Allow 21} 22func (d *dirEntFilter) Move(dst, src, span int) { 23 copy(d.ent[dst:dst+span], d.ent[src:src+span]) 24} 25 26// FilterDirEnt is used to filter a list of directory entries 27// by applying an ACL policy 28func FilterDirEnt(authorizer acl.Authorizer, ent structs.DirEntries) structs.DirEntries { 29 df := dirEntFilter{authorizer: authorizer, ent: ent} 30 return ent[:FilterEntries(&df)] 31} 32 33type txnResultsFilter struct { 34 authorizer acl.Authorizer 35 results structs.TxnResults 36} 37 38func (t *txnResultsFilter) Len() int { 39 return len(t.results) 40} 41 42func (t *txnResultsFilter) Filter(i int) bool { 43 result := t.results[i] 44 var authzContext acl.AuthorizerContext 45 switch { 46 case result.KV != nil: 47 result.KV.EnterpriseMeta.FillAuthzContext(&authzContext) 48 return t.authorizer.KeyRead(result.KV.Key, &authzContext) != acl.Allow 49 case result.Node != nil: 50 structs.WildcardEnterpriseMeta().FillAuthzContext(&authzContext) 51 return t.authorizer.NodeRead(result.Node.Node, &authzContext) != acl.Allow 52 case result.Service != nil: 53 result.Service.EnterpriseMeta.FillAuthzContext(&authzContext) 54 return t.authorizer.ServiceRead(result.Service.Service, &authzContext) != acl.Allow 55 case result.Check != nil: 56 result.Check.EnterpriseMeta.FillAuthzContext(&authzContext) 57 if result.Check.ServiceName != "" { 58 return t.authorizer.ServiceRead(result.Check.ServiceName, &authzContext) != acl.Allow 59 } 60 return t.authorizer.NodeRead(result.Check.Node, &authzContext) != acl.Allow 61 } 62 return false 63} 64 65func (t *txnResultsFilter) Move(dst, src, span int) { 66 copy(t.results[dst:dst+span], t.results[src:src+span]) 67} 68 69// FilterTxnResults is used to filter a list of transaction results by 70// applying an ACL policy. 71func FilterTxnResults(authorizer acl.Authorizer, results structs.TxnResults) structs.TxnResults { 72 rf := txnResultsFilter{authorizer: authorizer, results: results} 73 return results[:FilterEntries(&rf)] 74} 75 76// Filter interface is used with FilterEntries to do an 77// in-place filter of a slice. 78type Filter interface { 79 Len() int 80 Filter(int) bool 81 Move(dst, src, span int) 82} 83 84// FilterEntries is used to do an inplace filter of 85// a slice. This has cost proportional to the list length. 86func FilterEntries(f Filter) int { 87 // Compact the list 88 dst := 0 89 src := 0 90 n := f.Len() 91 for dst < n { 92 for src < n && f.Filter(src) { 93 src++ 94 } 95 if src == n { 96 break 97 } 98 end := src + 1 99 for end < n && !f.Filter(end) { 100 end++ 101 } 102 span := end - src 103 if span > 0 { 104 f.Move(dst, src, span) 105 dst += span 106 src += span 107 } 108 } 109 110 // Return the size of the slice 111 return dst 112} 113