git.frostfs.info/TrueCloudLab/frostfs-sdk-go@v0.0.0-20241022124111-5361f0ecebd3/eacl/validator_test.go (about) 1 package eacl 2 3 import ( 4 "crypto/rand" 5 "testing" 6 7 "github.com/stretchr/testify/require" 8 ) 9 10 func checkAction(t *testing.T, expected Action, v *Validator, vu *ValidationUnit) { 11 action, ok := v.CalculateAction(vu) 12 require.True(t, ok) 13 require.Equal(t, expected, action) 14 } 15 16 func checkDefaultAction(t *testing.T, v *Validator, vu *ValidationUnit) { 17 action, ok := v.CalculateAction(vu) 18 require.False(t, ok) 19 require.Equal(t, ActionAllow, action) 20 } 21 22 func TestFilterMatch(t *testing.T) { 23 tgt := *NewTarget() 24 tgt.SetRole(RoleOthers) 25 26 t.Run("simple header match", func(t *testing.T) { 27 tb := NewTable() 28 29 r := newRecord(ActionDeny, OperationUnknown, tgt) 30 r.AddFilter(HeaderFromObject, MatchStringEqual, "a", "xxx") 31 tb.AddRecord(r) 32 33 r = newRecord(ActionDeny, OperationUnknown, tgt) 34 r.AddFilter(HeaderFromRequest, MatchStringNotEqual, "b", "yyy") 35 tb.AddRecord(r) 36 37 tb.AddRecord(newRecord(ActionAllow, OperationUnknown, tgt)) 38 39 v := NewValidator() 40 vu := newValidationUnit(RoleOthers, nil, tb) 41 hs := headers{} 42 vu.hdrSrc = &hs 43 44 checkAction(t, ActionAllow, v, vu) 45 46 hs.obj = makeHeaders("b", "yyy") 47 checkAction(t, ActionAllow, v, vu) 48 49 hs.obj = makeHeaders("a", "xxx") 50 checkAction(t, ActionDeny, v, vu) 51 52 hs.obj = nil 53 hs.req = makeHeaders("b", "yyy") 54 checkAction(t, ActionAllow, v, vu) 55 56 hs.req = makeHeaders("b", "abc") 57 checkAction(t, ActionDeny, v, vu) 58 }) 59 60 t.Run("all filters must match", func(t *testing.T) { 61 tb := NewTable() 62 r := newRecord(ActionDeny, OperationUnknown, tgt) 63 r.AddFilter(HeaderFromObject, MatchStringEqual, "a", "xxx") 64 r.AddFilter(HeaderFromRequest, MatchStringEqual, "b", "yyy") 65 tb.AddRecord(r) 66 tb.AddRecord(newRecord(ActionAllow, OperationUnknown, tgt)) 67 68 v := NewValidator() 69 vu := newValidationUnit(RoleOthers, nil, tb) 70 hs := headers{} 71 vu.hdrSrc = &hs 72 73 hs.obj = makeHeaders("a", "xxx") 74 checkAction(t, ActionAllow, v, vu) 75 76 hs.req = makeHeaders("b", "yyy") 77 checkAction(t, ActionDeny, v, vu) 78 79 hs.obj = nil 80 checkAction(t, ActionAllow, v, vu) 81 }) 82 83 t.Run("filters with unknown type are skipped", func(t *testing.T) { 84 tb := NewTable() 85 r := newRecord(ActionDeny, OperationUnknown, tgt) 86 r.AddFilter(HeaderTypeUnknown, MatchStringEqual, "a", "xxx") 87 tb.AddRecord(r) 88 89 r = newRecord(ActionDeny, OperationUnknown, tgt) 90 r.AddFilter(0xFF, MatchStringEqual, "b", "yyy") 91 tb.AddRecord(r) 92 93 tb.AddRecord(newRecord(ActionDeny, OperationUnknown, tgt)) 94 95 v := NewValidator() 96 vu := newValidationUnit(RoleOthers, nil, tb) 97 hs := headers{} 98 vu.hdrSrc = &hs 99 100 checkDefaultAction(t, v, vu) 101 102 hs.obj = makeHeaders("a", "xxx") 103 checkDefaultAction(t, v, vu) 104 105 hs.obj = nil 106 hs.req = makeHeaders("b", "yyy") 107 checkDefaultAction(t, v, vu) 108 }) 109 110 t.Run("filters with match function are skipped", func(t *testing.T) { 111 tb := NewTable() 112 r := newRecord(ActionAllow, OperationUnknown, tgt) 113 r.AddFilter(HeaderFromObject, 0xFF, "a", "xxx") 114 tb.AddRecord(r) 115 tb.AddRecord(newRecord(ActionDeny, OperationUnknown, tgt)) 116 117 v := NewValidator() 118 vu := newValidationUnit(RoleOthers, nil, tb) 119 hs := headers{} 120 vu.hdrSrc = &hs 121 122 checkAction(t, ActionDeny, v, vu) 123 124 hs.obj = makeHeaders("a", "xxx") 125 checkAction(t, ActionDeny, v, vu) 126 }) 127 } 128 129 func TestOperationMatch(t *testing.T) { 130 tgt := *NewTarget() 131 tgt.SetRole(RoleOthers) 132 133 t.Run("single operation", func(t *testing.T) { 134 tb := NewTable() 135 tb.AddRecord(newRecord(ActionDeny, OperationPut, tgt)) 136 tb.AddRecord(newRecord(ActionAllow, OperationGet, tgt)) 137 138 v := NewValidator() 139 vu := newValidationUnit(RoleOthers, nil, tb) 140 141 vu.op = OperationPut 142 checkAction(t, ActionDeny, v, vu) 143 144 vu.op = OperationGet 145 checkAction(t, ActionAllow, v, vu) 146 }) 147 148 t.Run("unknown operation", func(t *testing.T) { 149 tb := NewTable() 150 tb.AddRecord(newRecord(ActionDeny, OperationUnknown, tgt)) 151 tb.AddRecord(newRecord(ActionAllow, OperationGet, tgt)) 152 153 v := NewValidator() 154 vu := newValidationUnit(RoleOthers, nil, tb) 155 156 // TODO discuss if both next tests should result in DENY 157 vu.op = OperationPut 158 checkDefaultAction(t, v, vu) 159 160 vu.op = OperationGet 161 checkAction(t, ActionAllow, v, vu) 162 }) 163 } 164 165 func TestTargetMatches(t *testing.T) { 166 pubs := makeKeys(t, 3) 167 168 tgt1 := NewTarget() 169 tgt1.SetBinaryKeys(pubs[0:2]) 170 tgt1.SetRole(RoleUser) 171 172 tgt2 := NewTarget() 173 tgt2.SetRole(RoleOthers) 174 175 r := NewRecord() 176 r.SetTargets(*tgt1, *tgt2) 177 178 u := newValidationUnit(RoleUser, pubs[0], nil) 179 require.True(t, targetMatches(u, r)) 180 181 u = newValidationUnit(RoleUser, pubs[2], nil) 182 require.False(t, targetMatches(u, r)) 183 184 u = newValidationUnit(RoleUnknown, pubs[1], nil) 185 require.True(t, targetMatches(u, r)) 186 187 u = newValidationUnit(RoleOthers, pubs[2], nil) 188 require.True(t, targetMatches(u, r)) 189 190 u = newValidationUnit(RoleSystem, pubs[2], nil) 191 require.False(t, targetMatches(u, r)) 192 } 193 194 func makeKeys(t *testing.T, n int) [][]byte { 195 pubs := make([][]byte, n) 196 for i := range pubs { 197 pubs[i] = make([]byte, 33) 198 pubs[i][0] = 0x02 199 200 _, err := rand.Read(pubs[i][1:]) 201 require.NoError(t, err) 202 } 203 return pubs 204 } 205 206 type ( 207 hdr struct { 208 key, value string 209 } 210 211 headers struct { 212 obj []Header 213 req []Header 214 } 215 ) 216 217 func (h hdr) Key() string { return h.key } 218 func (h hdr) Value() string { return h.value } 219 220 func makeHeaders(kv ...string) []Header { 221 hs := make([]Header, len(kv)/2) 222 for i := 0; i < len(kv); i += 2 { 223 hs[i/2] = hdr{kv[i], kv[i+1]} 224 } 225 return hs 226 } 227 228 func (h headers) HeadersOfType(ht FilterHeaderType) ([]Header, bool) { 229 switch ht { 230 case HeaderFromRequest: 231 return h.req, true 232 case HeaderFromObject: 233 return h.obj, true 234 default: 235 return nil, false 236 } 237 } 238 239 func newRecord(a Action, op Operation, tgt ...Target) *Record { 240 r := NewRecord() 241 r.SetAction(a) 242 r.SetOperation(op) 243 r.SetTargets(tgt...) 244 return r 245 } 246 247 func newValidationUnit(role Role, key []byte, table *Table) *ValidationUnit { 248 return new(ValidationUnit). 249 WithRole(role). 250 WithSenderKey(key). 251 WithEACLTable(table) 252 }