github.com/ethersphere/bee/v2@v2.2.0/pkg/accesscontrol/controller_test.go (about) 1 // Copyright 2024 The Swarm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package accesscontrol_test 6 7 import ( 8 "context" 9 "crypto/ecdsa" 10 "reflect" 11 "testing" 12 "time" 13 14 "github.com/ethersphere/bee/v2/pkg/accesscontrol" 15 "github.com/ethersphere/bee/v2/pkg/accesscontrol/kvs" 16 encryption "github.com/ethersphere/bee/v2/pkg/encryption" 17 "github.com/ethersphere/bee/v2/pkg/file" 18 "github.com/ethersphere/bee/v2/pkg/file/loadsave" 19 "github.com/ethersphere/bee/v2/pkg/file/redundancy" 20 "github.com/ethersphere/bee/v2/pkg/swarm" 21 "github.com/stretchr/testify/assert" 22 "github.com/stretchr/testify/require" 23 "golang.org/x/crypto/sha3" 24 ) 25 26 //nolint:errcheck,gosec,wrapcheck 27 func getHistoryFixture(t *testing.T, ctx context.Context, ls file.LoadSaver, al accesscontrol.ActLogic, publisher *ecdsa.PublicKey) (swarm.Address, error) { 28 t.Helper() 29 h, err := accesscontrol.NewHistory(ls) 30 if err != nil { 31 return swarm.ZeroAddress, err 32 } 33 pk1 := getPrivKey(1) 34 pk2 := getPrivKey(2) 35 36 kvs0, err := kvs.New(ls) 37 assertNoError(t, "kvs0 create", err) 38 al.AddGrantee(ctx, kvs0, publisher, publisher) 39 kvs0Ref, err := kvs0.Save(ctx) 40 assertNoError(t, "kvs0 save", err) 41 kvs1, err := kvs.New(ls) 42 assertNoError(t, "kvs1 create", err) 43 al.AddGrantee(ctx, kvs1, publisher, publisher) 44 al.AddGrantee(ctx, kvs1, publisher, &pk1.PublicKey) 45 kvs1Ref, err := kvs1.Save(ctx) 46 assertNoError(t, "kvs1 save", err) 47 kvs2, err := kvs.New(ls) 48 assertNoError(t, "kvs2 create", err) 49 al.AddGrantee(ctx, kvs2, publisher, publisher) 50 al.AddGrantee(ctx, kvs2, publisher, &pk2.PublicKey) 51 kvs2Ref, err := kvs2.Save(ctx) 52 assertNoError(t, "kvs2 save", err) 53 firstTime := time.Date(1994, time.April, 1, 0, 0, 0, 0, time.UTC).Unix() 54 secondTime := time.Date(2000, time.April, 1, 0, 0, 0, 0, time.UTC).Unix() 55 thirdTime := time.Date(2015, time.April, 1, 0, 0, 0, 0, time.UTC).Unix() 56 57 h.Add(ctx, kvs0Ref, &thirdTime, nil) 58 h.Add(ctx, kvs1Ref, &firstTime, nil) 59 h.Add(ctx, kvs2Ref, &secondTime, nil) 60 return h.Store(ctx) 61 } 62 63 func TestController_UploadHandler(t *testing.T) { 64 t.Parallel() 65 ctx := context.Background() 66 publisher := getPrivKey(0) 67 diffieHellman := accesscontrol.NewDefaultSession(publisher) 68 al := accesscontrol.NewLogic(diffieHellman) 69 c := accesscontrol.NewController(al) 70 ls := createLs() 71 72 t.Run("New upload", func(t *testing.T) { 73 ref := swarm.RandAddress(t) 74 _, hRef, encRef, err := c.UploadHandler(ctx, ls, ref, &publisher.PublicKey, swarm.ZeroAddress) 75 assertNoError(t, "UploadHandler", err) 76 77 h, err := accesscontrol.NewHistoryReference(ls, hRef) 78 assertNoError(t, "create history ref", err) 79 entry, err := h.Lookup(ctx, time.Now().Unix()) 80 assertNoError(t, "history lookup", err) 81 actRef := entry.Reference() 82 act, err := kvs.NewReference(ls, actRef) 83 assertNoError(t, "kvs create ref", err) 84 expRef, err := al.EncryptRef(ctx, act, &publisher.PublicKey, ref) 85 86 assertNoError(t, "encrypt ref", err) 87 assert.Equal(t, encRef, expRef) 88 assert.NotEqual(t, hRef, swarm.ZeroAddress) 89 }) 90 91 t.Run("Upload to same history", func(t *testing.T) { 92 ref := swarm.RandAddress(t) 93 _, hRef1, _, err := c.UploadHandler(ctx, ls, ref, &publisher.PublicKey, swarm.ZeroAddress) 94 assertNoError(t, "1st upload", err) 95 _, hRef2, encRef, err := c.UploadHandler(ctx, ls, ref, &publisher.PublicKey, hRef1) 96 assertNoError(t, "2nd upload", err) 97 h, err := accesscontrol.NewHistoryReference(ls, hRef2) 98 assertNoError(t, "create history ref", err) 99 hRef2, err = h.Store(ctx) 100 assertNoError(t, "store history", err) 101 assert.True(t, hRef1.Equal(hRef2)) 102 103 h, err = accesscontrol.NewHistoryReference(ls, hRef2) 104 assertNoError(t, "create history ref", err) 105 entry, err := h.Lookup(ctx, time.Now().Unix()) 106 assertNoError(t, "history lookup", err) 107 actRef := entry.Reference() 108 act, err := kvs.NewReference(ls, actRef) 109 assertNoError(t, "kvs create ref", err) 110 expRef, err := al.EncryptRef(ctx, act, &publisher.PublicKey, ref) 111 112 assertNoError(t, "encrypt ref", err) 113 assert.Equal(t, expRef, encRef) 114 assert.NotEqual(t, hRef2, swarm.ZeroAddress) 115 }) 116 } 117 118 func TestController_PublisherDownload(t *testing.T) { 119 t.Parallel() 120 ctx := context.Background() 121 publisher := getPrivKey(0) 122 diffieHellman := accesscontrol.NewDefaultSession(publisher) 123 al := accesscontrol.NewLogic(diffieHellman) 124 c := accesscontrol.NewController(al) 125 ls := createLs() 126 ref := swarm.RandAddress(t) 127 href, err := getHistoryFixture(t, ctx, ls, al, &publisher.PublicKey) 128 assertNoError(t, "history fixture create", err) 129 h, err := accesscontrol.NewHistoryReference(ls, href) 130 assertNoError(t, "create history ref", err) 131 entry, err := h.Lookup(ctx, time.Now().Unix()) 132 assertNoError(t, "history lookup", err) 133 actRef := entry.Reference() 134 act, err := kvs.NewReference(ls, actRef) 135 assertNoError(t, "kvs create ref", err) 136 encRef, err := al.EncryptRef(ctx, act, &publisher.PublicKey, ref) 137 assertNoError(t, "encrypt ref", err) 138 139 dref, err := c.DownloadHandler(ctx, ls, encRef, &publisher.PublicKey, href, time.Now().Unix()) 140 assertNoError(t, "download by publisher", err) 141 assert.Equal(t, ref, dref) 142 } 143 144 func TestController_GranteeDownload(t *testing.T) { 145 t.Parallel() 146 ctx := context.Background() 147 publisher := getPrivKey(0) 148 grantee := getPrivKey(2) 149 publisherDH := accesscontrol.NewDefaultSession(publisher) 150 publisherAL := accesscontrol.NewLogic(publisherDH) 151 152 diffieHellman := accesscontrol.NewDefaultSession(grantee) 153 al := accesscontrol.NewLogic(diffieHellman) 154 ls := createLs() 155 c := accesscontrol.NewController(al) 156 ref := swarm.RandAddress(t) 157 href, err := getHistoryFixture(t, ctx, ls, publisherAL, &publisher.PublicKey) 158 assertNoError(t, "history fixture create", err) 159 h, err := accesscontrol.NewHistoryReference(ls, href) 160 assertNoError(t, "history fixture create", err) 161 ts := time.Date(2001, time.April, 1, 0, 0, 0, 0, time.UTC).Unix() 162 entry, err := h.Lookup(ctx, ts) 163 assertNoError(t, "history lookup", err) 164 actRef := entry.Reference() 165 act, err := kvs.NewReference(ls, actRef) 166 assertNoError(t, "kvs create ref", err) 167 encRef, err := publisherAL.EncryptRef(ctx, act, &publisher.PublicKey, ref) 168 169 assertNoError(t, "encrypt ref", err) 170 dref, err := c.DownloadHandler(ctx, ls, encRef, &publisher.PublicKey, href, ts) 171 assertNoError(t, "download by grantee", err) 172 assert.Equal(t, ref, dref) 173 } 174 175 func TestController_UpdateHandler(t *testing.T) { 176 t.Parallel() 177 ctx := context.Background() 178 publisher := getPrivKey(1) 179 diffieHellman := accesscontrol.NewDefaultSession(publisher) 180 al := accesscontrol.NewLogic(diffieHellman) 181 keys, err := al.Session.Key(&publisher.PublicKey, [][]byte{{1}}) 182 assertNoError(t, "Session key", err) 183 refCipher := encryption.New(keys[0], 0, 0, sha3.NewLegacyKeccak256) 184 ls := createLs() 185 gls := loadsave.New(mockStorer.ChunkStore(), mockStorer.Cache(), requestPipelineFactory(context.Background(), mockStorer.Cache(), true, redundancy.NONE)) 186 c := accesscontrol.NewController(al) 187 href, err := getHistoryFixture(t, ctx, ls, al, &publisher.PublicKey) 188 assertNoError(t, "history fixture create", err) 189 190 grantee1 := getPrivKey(0) 191 grantee := getPrivKey(2) 192 193 t.Run("add to new list", func(t *testing.T) { 194 addList := []*ecdsa.PublicKey{&grantee.PublicKey} 195 granteeRef, _, _, _, err := c.UpdateHandler(ctx, ls, ls, swarm.ZeroAddress, swarm.ZeroAddress, &publisher.PublicKey, addList, nil) 196 assertNoError(t, "UpdateHandlererror", err) 197 198 gl, err := accesscontrol.NewGranteeListReference(ctx, ls, granteeRef) 199 200 assertNoError(t, "create granteelist ref", err) 201 assert.Len(t, gl.Get(), 1) 202 }) 203 t.Run("add to existing list", func(t *testing.T) { 204 addList := []*ecdsa.PublicKey{&grantee.PublicKey} 205 granteeRef, eglref, _, _, err := c.UpdateHandler(ctx, ls, gls, swarm.ZeroAddress, href, &publisher.PublicKey, addList, nil) 206 assertNoError(t, "UpdateHandlererror", err) 207 208 gl, err := accesscontrol.NewGranteeListReference(ctx, ls, granteeRef) 209 210 assertNoError(t, "create granteelist ref", err) 211 assert.Len(t, gl.Get(), 1) 212 213 addList = []*ecdsa.PublicKey{&getPrivKey(0).PublicKey} 214 granteeRef, _, _, _, err = c.UpdateHandler(ctx, ls, ls, eglref, href, &publisher.PublicKey, addList, nil) 215 assertNoError(t, "UpdateHandler", err) 216 gl, err = accesscontrol.NewGranteeListReference(ctx, ls, granteeRef) 217 assertNoError(t, "create granteelist ref", err) 218 assert.Len(t, gl.Get(), 2) 219 }) 220 t.Run("add and revoke", func(t *testing.T) { 221 addList := []*ecdsa.PublicKey{&grantee.PublicKey} 222 revokeList := []*ecdsa.PublicKey{&grantee1.PublicKey} 223 gl := accesscontrol.NewGranteeList(ls) 224 err = gl.Add([]*ecdsa.PublicKey{&publisher.PublicKey, &grantee1.PublicKey}) 225 granteeRef, err := gl.Save(ctx) 226 assertNoError(t, "granteelist save", err) 227 eglref, err := refCipher.Encrypt(granteeRef.Bytes()) 228 assertNoError(t, "encrypt granteeref", err) 229 230 granteeRef, _, _, _, err = c.UpdateHandler(ctx, ls, gls, swarm.NewAddress(eglref), href, &publisher.PublicKey, addList, revokeList) 231 assertNoError(t, "UpdateHandler", err) 232 gl, err = accesscontrol.NewGranteeListReference(ctx, ls, granteeRef) 233 234 assertNoError(t, "create granteelist ref", err) 235 assert.Len(t, gl.Get(), 2) 236 }) 237 t.Run("add and revoke then get from history", func(t *testing.T) { 238 addRevokeList := []*ecdsa.PublicKey{&grantee.PublicKey} 239 ref := swarm.RandAddress(t) 240 _, hRef, encRef, err := c.UploadHandler(ctx, ls, ref, &publisher.PublicKey, swarm.ZeroAddress) 241 require.NoError(t, err) 242 243 // Need to wait a second before each update call so that a new history mantaray fork is created for the new key(timestamp) entry 244 time.Sleep(1 * time.Second) 245 beforeRevokeTS := time.Now().Unix() 246 _, egranteeRef, hrefUpdate1, _, err := c.UpdateHandler(ctx, ls, gls, swarm.ZeroAddress, hRef, &publisher.PublicKey, addRevokeList, nil) 247 require.NoError(t, err) 248 249 time.Sleep(1 * time.Second) 250 granteeRef, _, hrefUpdate2, _, err := c.UpdateHandler(ctx, ls, gls, egranteeRef, hrefUpdate1, &publisher.PublicKey, nil, addRevokeList) 251 require.NoError(t, err) 252 253 gl, err := accesscontrol.NewGranteeListReference(ctx, ls, granteeRef) 254 require.NoError(t, err) 255 assert.Empty(t, gl.Get()) 256 // expect history reference to be different after grantee list update 257 assert.NotEqual(t, hrefUpdate1, hrefUpdate2) 258 259 granteeDH := accesscontrol.NewDefaultSession(grantee) 260 granteeAl := accesscontrol.NewLogic(granteeDH) 261 granteeCtrl := accesscontrol.NewController(granteeAl) 262 // download with grantee shall still work with the timestamp before the revoke 263 decRef, err := granteeCtrl.DownloadHandler(ctx, ls, encRef, &publisher.PublicKey, hrefUpdate2, beforeRevokeTS) 264 require.NoError(t, err) 265 assert.Equal(t, ref, decRef) 266 267 // download with grantee shall NOT work with the latest timestamp 268 decRef, err = granteeCtrl.DownloadHandler(ctx, ls, encRef, &publisher.PublicKey, hrefUpdate2, time.Now().Unix()) 269 require.Error(t, err) 270 assert.Equal(t, swarm.ZeroAddress, decRef) 271 272 // publisher shall still be able to download with the timestamp before the revoke 273 decRef, err = c.DownloadHandler(ctx, ls, encRef, &publisher.PublicKey, hrefUpdate2, beforeRevokeTS) 274 require.NoError(t, err) 275 assert.Equal(t, ref, decRef) 276 }) 277 t.Run("add twice", func(t *testing.T) { 278 addList := []*ecdsa.PublicKey{&grantee.PublicKey, &grantee.PublicKey} 279 //nolint:ineffassign,staticcheck,wastedassign 280 granteeRef, eglref, _, _, err := c.UpdateHandler(ctx, ls, gls, swarm.ZeroAddress, href, &publisher.PublicKey, addList, nil) 281 granteeRef, _, _, _, err = c.UpdateHandler(ctx, ls, ls, eglref, href, &publisher.PublicKey, addList, nil) 282 assertNoError(t, "UpdateHandler", err) 283 gl, err := accesscontrol.NewGranteeListReference(ctx, ls, granteeRef) 284 285 assertNoError(t, "create granteelist ref", err) 286 assert.Len(t, gl.Get(), 1) 287 }) 288 t.Run("revoke non-existing", func(t *testing.T) { 289 addList := []*ecdsa.PublicKey{&grantee.PublicKey} 290 granteeRef, _, _, _, err := c.UpdateHandler(ctx, ls, ls, swarm.ZeroAddress, href, &publisher.PublicKey, addList, nil) 291 assertNoError(t, "UpdateHandler", err) 292 gl, err := accesscontrol.NewGranteeListReference(ctx, ls, granteeRef) 293 294 assertNoError(t, "create granteelist ref", err) 295 assert.Len(t, gl.Get(), 1) 296 }) 297 } 298 299 func TestController_Get(t *testing.T) { 300 t.Parallel() 301 ctx := context.Background() 302 publisher := getPrivKey(1) 303 caller := getPrivKey(0) 304 grantee := getPrivKey(2) 305 diffieHellman1 := accesscontrol.NewDefaultSession(publisher) 306 diffieHellman2 := accesscontrol.NewDefaultSession(caller) 307 al1 := accesscontrol.NewLogic(diffieHellman1) 308 al2 := accesscontrol.NewLogic(diffieHellman2) 309 ls := createLs() 310 gls := loadsave.New(mockStorer.ChunkStore(), mockStorer.Cache(), requestPipelineFactory(context.Background(), mockStorer.Cache(), true, redundancy.NONE)) 311 c1 := accesscontrol.NewController(al1) 312 c2 := accesscontrol.NewController(al2) 313 314 t.Run("get by publisher", func(t *testing.T) { 315 addList := []*ecdsa.PublicKey{&grantee.PublicKey} 316 granteeRef, eglRef, _, _, err := c1.UpdateHandler(ctx, ls, gls, swarm.ZeroAddress, swarm.ZeroAddress, &publisher.PublicKey, addList, nil) 317 assertNoError(t, "UpdateHandler", err) 318 319 grantees, err := c1.Get(ctx, ls, &publisher.PublicKey, eglRef) 320 assertNoError(t, "get by publisher", err) 321 assert.True(t, reflect.DeepEqual(grantees, addList)) 322 323 gl, err := accesscontrol.NewGranteeListReference(ctx, ls, granteeRef) 324 assertNoError(t, "create granteelist ref", err) 325 assert.True(t, reflect.DeepEqual(gl.Get(), addList)) 326 }) 327 t.Run("get by non-publisher", func(t *testing.T) { 328 addList := []*ecdsa.PublicKey{&grantee.PublicKey} 329 _, eglRef, _, _, err := c1.UpdateHandler(ctx, ls, gls, swarm.ZeroAddress, swarm.ZeroAddress, &publisher.PublicKey, addList, nil) 330 assertNoError(t, "UpdateHandler", err) 331 grantees, err := c2.Get(ctx, ls, &publisher.PublicKey, eglRef) 332 assertError(t, "controller get by non-publisher", err) 333 assert.Nil(t, grantees) 334 }) 335 }