git.frostfs.info/TrueCloudLab/frostfs-sdk-go@v0.0.0-20241022124111-5361f0ecebd3/eacl/record.go (about) 1 package eacl 2 3 import ( 4 "crypto/ecdsa" 5 6 v2acl "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl" 7 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/checksum" 8 cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" 9 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" 10 oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" 11 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user" 12 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/version" 13 ) 14 15 // Record of the ContainerEACL rule, that defines ContainerEACL action, targets for this action, 16 // object service operation and filters for request headers. 17 // 18 // Record is compatible with v2 acl.EACLRecord message. 19 type Record struct { 20 action Action 21 operation Operation 22 filters []Filter 23 targets []Target 24 } 25 26 // Targets returns list of target subjects to apply ACL rule to. 27 func (r Record) Targets() []Target { 28 return r.targets 29 } 30 31 // SetTargets sets list of target subjects to apply ACL rule to. 32 func (r *Record) SetTargets(targets ...Target) { 33 r.targets = targets 34 } 35 36 // Filters returns list of filters to match and see if rule is applicable. 37 func (r Record) Filters() []Filter { 38 return r.filters 39 } 40 41 // Operation returns FrostFS request verb to match. 42 func (r Record) Operation() Operation { 43 return r.operation 44 } 45 46 // SetOperation sets FrostFS request verb to match. 47 func (r *Record) SetOperation(operation Operation) { 48 r.operation = operation 49 } 50 51 // Action returns rule execution result. 52 func (r Record) Action() Action { 53 return r.action 54 } 55 56 // SetAction sets rule execution result. 57 func (r *Record) SetAction(action Action) { 58 r.action = action 59 } 60 61 // AddRecordTarget adds single Target to the Record. 62 func AddRecordTarget(r *Record, t *Target) { 63 r.SetTargets(append(r.Targets(), *t)...) 64 } 65 66 // AddFormedTarget forms Target with specified Role and list of 67 // ECDSA public keys and adds it to the Record. 68 func AddFormedTarget(r *Record, role Role, keys ...ecdsa.PublicKey) { 69 t := NewTarget() 70 t.SetRole(role) 71 72 SetTargetECDSAKeys(t, ecdsaKeysToPtrs(keys)...) 73 AddRecordTarget(r, t) 74 } 75 76 type stringEncoder interface { 77 EncodeToString() string 78 } 79 80 func (r *Record) addFilter(from FilterHeaderType, m Match, keyTyp filterKeyType, key string, val stringEncoder) { 81 filter := Filter{ 82 from: from, 83 key: filterKey{ 84 typ: keyTyp, 85 str: key, 86 }, 87 matcher: m, 88 value: val, 89 } 90 91 r.filters = append(r.filters, filter) 92 } 93 94 func (r *Record) addObjectFilter(m Match, keyTyp filterKeyType, key string, val stringEncoder) { 95 r.addFilter(HeaderFromObject, m, keyTyp, key, val) 96 } 97 98 func (r *Record) addObjectReservedFilter(m Match, typ filterKeyType, val stringEncoder) { 99 r.addObjectFilter(m, typ, "", val) 100 } 101 102 // AddFilter adds generic filter. 103 func (r *Record) AddFilter(from FilterHeaderType, matcher Match, name, value string) { 104 r.addFilter(from, matcher, 0, name, staticStringer(value)) 105 } 106 107 // AddObjectAttributeFilter adds filter by object attribute. 108 func (r *Record) AddObjectAttributeFilter(m Match, key, value string) { 109 r.addObjectFilter(m, 0, key, staticStringer(value)) 110 } 111 112 // AddObjectVersionFilter adds filter by object version. 113 func (r *Record) AddObjectVersionFilter(m Match, v *version.Version) { 114 r.addObjectReservedFilter(m, fKeyObjVersion, staticStringer(version.EncodeToString(*v))) 115 } 116 117 // AddObjectIDFilter adds filter by object ID. 118 func (r *Record) AddObjectIDFilter(m Match, id oid.ID) { 119 r.addObjectReservedFilter(m, fKeyObjID, id) 120 } 121 122 // AddObjectContainerIDFilter adds filter by object container ID. 123 func (r *Record) AddObjectContainerIDFilter(m Match, id cid.ID) { 124 r.addObjectReservedFilter(m, fKeyObjContainerID, id) 125 } 126 127 // AddObjectOwnerIDFilter adds filter by object owner ID. 128 func (r *Record) AddObjectOwnerIDFilter(m Match, id user.ID) { 129 r.addObjectReservedFilter(m, fKeyObjOwnerID, id) 130 } 131 132 // AddObjectCreationEpoch adds filter by object creation epoch. 133 func (r *Record) AddObjectCreationEpoch(m Match, epoch uint64) { 134 r.addObjectReservedFilter(m, fKeyObjCreationEpoch, u64Stringer(epoch)) 135 } 136 137 // AddObjectPayloadLengthFilter adds filter by object payload length. 138 func (r *Record) AddObjectPayloadLengthFilter(m Match, size uint64) { 139 r.addObjectReservedFilter(m, fKeyObjPayloadLength, u64Stringer(size)) 140 } 141 142 // AddObjectPayloadHashFilter adds filter by object payload hash value. 143 func (r *Record) AddObjectPayloadHashFilter(m Match, h checksum.Checksum) { 144 r.addObjectReservedFilter(m, fKeyObjPayloadHash, staticStringer(h.String())) 145 } 146 147 // AddObjectTypeFilter adds filter by object type. 148 func (r *Record) AddObjectTypeFilter(m Match, t object.Type) { 149 r.addObjectReservedFilter(m, fKeyObjType, staticStringer(t.String())) 150 } 151 152 // AddObjectHomomorphicHashFilter adds filter by object payload homomorphic hash value. 153 func (r *Record) AddObjectHomomorphicHashFilter(m Match, h checksum.Checksum) { 154 r.addObjectReservedFilter(m, fKeyObjHomomorphicHash, staticStringer(h.String())) 155 } 156 157 // ToV2 converts Record to v2 acl.EACLRecord message. 158 // 159 // Nil Record converts to nil. 160 func (r *Record) ToV2() *v2acl.Record { 161 if r == nil { 162 return nil 163 } 164 165 v2 := new(v2acl.Record) 166 167 if r.targets != nil { 168 targets := make([]v2acl.Target, len(r.targets)) 169 for i := range r.targets { 170 targets[i] = *r.targets[i].ToV2() 171 } 172 173 v2.SetTargets(targets) 174 } 175 176 if r.filters != nil { 177 filters := make([]v2acl.HeaderFilter, len(r.filters)) 178 for i := range r.filters { 179 filters[i] = *r.filters[i].ToV2() 180 } 181 182 v2.SetFilters(filters) 183 } 184 185 v2.SetAction(r.action.ToV2()) 186 v2.SetOperation(r.operation.ToV2()) 187 188 return v2 189 } 190 191 // NewRecord creates and returns blank Record instance. 192 // 193 // Defaults: 194 // - action: ActionUnknown; 195 // - operation: OperationUnknown; 196 // - targets: nil, 197 // - filters: nil. 198 func NewRecord() *Record { 199 return new(Record) 200 } 201 202 // CreateRecord creates, initializes with parameters and returns Record instance. 203 func CreateRecord(action Action, operation Operation) *Record { 204 r := NewRecord() 205 r.action = action 206 r.operation = operation 207 r.targets = []Target{} 208 r.filters = []Filter{} 209 210 return r 211 } 212 213 // NewRecordFromV2 converts v2 acl.EACLRecord message to Record. 214 func NewRecordFromV2(record *v2acl.Record) *Record { 215 r := NewRecord() 216 217 if record == nil { 218 return r 219 } 220 221 r.action = ActionFromV2(record.GetAction()) 222 r.operation = OperationFromV2(record.GetOperation()) 223 224 v2targets := record.GetTargets() 225 v2filters := record.GetFilters() 226 227 r.targets = make([]Target, len(v2targets)) 228 for i := range v2targets { 229 r.targets[i] = *NewTargetFromV2(&v2targets[i]) 230 } 231 232 r.filters = make([]Filter, len(v2filters)) 233 for i := range v2filters { 234 r.filters[i] = *NewFilterFromV2(&v2filters[i]) 235 } 236 237 return r 238 } 239 240 // Marshal marshals Record into a protobuf binary form. 241 func (r *Record) Marshal() ([]byte, error) { 242 return r.ToV2().StableMarshal(nil), nil 243 } 244 245 // Unmarshal unmarshals protobuf binary representation of Record. 246 func (r *Record) Unmarshal(data []byte) error { 247 fV2 := new(v2acl.Record) 248 if err := fV2.Unmarshal(data); err != nil { 249 return err 250 } 251 252 *r = *NewRecordFromV2(fV2) 253 254 return nil 255 } 256 257 // MarshalJSON encodes Record to protobuf JSON format. 258 func (r *Record) MarshalJSON() ([]byte, error) { 259 return r.ToV2().MarshalJSON() 260 } 261 262 // UnmarshalJSON decodes Record from protobuf JSON format. 263 func (r *Record) UnmarshalJSON(data []byte) error { 264 tV2 := new(v2acl.Record) 265 if err := tV2.UnmarshalJSON(data); err != nil { 266 return err 267 } 268 269 *r = *NewRecordFromV2(tV2) 270 271 return nil 272 } 273 274 // equalRecords compares Record with each other. 275 func equalRecords(r1, r2 Record) bool { 276 if r1.Operation() != r2.Operation() || 277 r1.Action() != r2.Action() { 278 return false 279 } 280 281 fs1, fs2 := r1.Filters(), r2.Filters() 282 ts1, ts2 := r1.Targets(), r2.Targets() 283 284 if len(fs1) != len(fs2) || 285 len(ts1) != len(ts2) { 286 return false 287 } 288 289 for i := range len(fs1) { 290 if !equalFilters(fs1[i], fs2[i]) { 291 return false 292 } 293 } 294 295 for i := range len(ts1) { 296 if !equalTargets(ts1[i], ts2[i]) { 297 return false 298 } 299 } 300 301 return true 302 }