Skip to content

Commit 6ee2c2e

Browse files
committed
PR(MAIN): Gate & Test - Verify Signature
1 parent 9da34cc commit 6ee2c2e

5 files changed

Lines changed: 323 additions & 0 deletions

File tree

acp/types/types.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ const (
9595
AdminSchemaPatchPerm
9696
AdminPatchCollectionPerm
9797
AdminNodeGetIdentityPerm
98+
AdminVerifySignaturePerm
9899
)
99100

100101
// List of all valid resource interface permissions for admin access control, the order of
@@ -122,6 +123,7 @@ var RequiredResourcePermissionsForAdmin = []string{
122123
"schema-patch",
123124
"patch-collection",
124125
"node-get-identity",
126+
"verify-signature",
125127
}
126128

127129
const InternalAdminACPObjectToGate = "NodeObject"
@@ -180,6 +182,8 @@ resources:
180182
expr: owner + admin
181183
node-get-identity:
182184
expr: owner + admin
185+
verify-signature:
186+
expr: owner + admin
183187
184188
relations:
185189
owner:

internal/db/verify.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ import (
2929
// VerifySignature verifies the signatures of a block using a public key.
3030
// Returns an error if any signature verification fails.
3131
func (db *DB) VerifySignature(ctx context.Context, blockCid string, pubKey crypto.PublicKey) error {
32+
if err := db.checkAdminAccess(ctx, acpTypes.AdminVerifySignaturePerm); err != nil {
33+
return err
34+
}
35+
3236
parsedCid, err := cid.Parse(blockCid)
3337
if err != nil {
3438
return err
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
// Copyright 2025 Democratized Data Foundation
2+
//
3+
// Use of this software is governed by the Business Source License
4+
// included in the file licenses/BSL.txt.
5+
//
6+
// As of the Change Date specified in that file, in accordance with
7+
// the Business Source License, use of this software will be governed
8+
// by the Apache License, Version 2.0, included in the file
9+
// licenses/APL.txt.
10+
11+
package test_acp_aac_setup_then_start
12+
13+
import (
14+
"testing"
15+
16+
"github.com/sourcenetwork/immutable"
17+
18+
testUtils "github.com/sourcenetwork/defradb/tests/integration"
19+
)
20+
21+
func TestAAC_GatesVerifySignaturePreSetup_AllowIfAuthorizedElseError(t *testing.T) {
22+
test := testUtils.TestCase{
23+
Description: "admin acp correctly gates verify signature operation (setup before aac), allow if authorized, otherwise error",
24+
SupportedDatabaseTypes: immutable.Some(
25+
[]testUtils.DatabaseType{
26+
// This test only supports file type databases since the setup steps will be done before
27+
// the node is re-started with aac enabled (if it's in-memory it will loose setup state).
28+
testUtils.BadgerFileType,
29+
},
30+
),
31+
SupportedClientTypes: immutable.Some(
32+
[]testUtils.ClientType{
33+
// Default signer can be only tested with HTTP and CLI clients, because with Go client
34+
// when providing an identity, it includes the private key.
35+
testUtils.HTTPClientType,
36+
testUtils.CLIClientType,
37+
},
38+
),
39+
EnableSigning: true,
40+
Actions: []any{
41+
// Note: Since this is not an in-memory test, we can do the setup steps before aac is enabled.
42+
testUtils.SchemaUpdate{
43+
Schema: `
44+
type Users {
45+
name: String
46+
age: Int
47+
}`,
48+
},
49+
testUtils.CreateDoc{
50+
DocMap: map[string]any{
51+
"name": "John",
52+
"age": 21,
53+
},
54+
},
55+
56+
// Starting with ACC, so only authorized user(s) can perform operations from here on out.
57+
testUtils.Close{},
58+
testUtils.Start{
59+
Identity: testUtils.ClientIdentity(1),
60+
EnableAAC: true,
61+
},
62+
63+
// We haven't authorized non-identities. So, this should error.
64+
testUtils.VerifyBlockSignature{
65+
Identity: testUtils.NoIdentity(),
66+
SignerIdentity: testUtils.NodeIdentity(0).Value(),
67+
Cid: "bafyreicwhd5s762awsrx6eowwqkkfpq7r5nnjosiru7blgaxo32wx6enp4",
68+
ExpectedError: "not authorized to perform operation",
69+
},
70+
71+
// Wrong user/identity will also not be authorized.
72+
testUtils.VerifyBlockSignature{
73+
Identity: testUtils.ClientIdentity(2),
74+
SignerIdentity: testUtils.NodeIdentity(0).Value(),
75+
Cid: "bafyreicwhd5s762awsrx6eowwqkkfpq7r5nnjosiru7blgaxo32wx6enp4",
76+
ExpectedError: "not authorized to perform operation",
77+
},
78+
79+
// This should work as the identity is authorized.
80+
testUtils.VerifyBlockSignature{
81+
Identity: testUtils.ClientIdentity(1),
82+
SignerIdentity: testUtils.NodeIdentity(0).Value(),
83+
Cid: "bafyreicwhd5s762awsrx6eowwqkkfpq7r5nnjosiru7blgaxo32wx6enp4",
84+
},
85+
},
86+
}
87+
88+
testUtils.ExecuteTestCase(t, test)
89+
}
90+
91+
func TestAAC_GatesVerifySignatureGo_AllowIfAuthorizedElseError(t *testing.T) {
92+
test := testUtils.TestCase{
93+
Description: "admin acp correctly gates verify signature operation (go client & setup before aac), allow if authorized, otherwise error",
94+
EnableSigning: true,
95+
SupportedDatabaseTypes: immutable.Some(
96+
[]testUtils.DatabaseType{
97+
// This test only supports file type databases since the setup steps will be done before
98+
// the node is re-started with aac enabled (if it's in-memory it will loose setup state).
99+
testUtils.BadgerFileType,
100+
},
101+
),
102+
SupportedClientTypes: immutable.Some(
103+
[]testUtils.ClientType{
104+
// Creating of signed documents over HTTP is not supported yet, because signing
105+
// requires a private key which we do not pass over HTTP.
106+
testUtils.GoClientType,
107+
},
108+
),
109+
Actions: []any{
110+
// Starting with ACC, so only authorized user(s) can perform operations from here on out.
111+
testUtils.Close{},
112+
testUtils.Start{
113+
Identity: testUtils.ClientIdentity(1),
114+
EnableAAC: true,
115+
},
116+
// Note: Doing setup steps after starting with aac enabled, otherwise the in-memory tests
117+
// will loose setup state when the restart happens (i.e. the restart that started aac).
118+
testUtils.SchemaUpdate{
119+
Identity: testUtils.ClientIdentity(1),
120+
Schema: `
121+
type Users {
122+
name: String
123+
age: Int
124+
}`,
125+
},
126+
testUtils.CreateDoc{
127+
Identity: testUtils.ClientIdentity(1),
128+
DocMap: map[string]any{
129+
"name": "John",
130+
"age": 21,
131+
},
132+
},
133+
// Note: Setup is now done, the test code that follows is what we want to assert.
134+
135+
// We haven't authorized non-identities. So, this should error.
136+
testUtils.VerifyBlockSignature{
137+
Identity: testUtils.NoIdentity(),
138+
SignerIdentity: testUtils.ClientIdentity(1).Value(),
139+
Cid: "bafyreicwhd5s762awsrx6eowwqkkfpq7r5nnjosiru7blgaxo32wx6enp4",
140+
ExpectedError: "not authorized to perform operation",
141+
},
142+
143+
// Wrong user/identity will also not be authorized.
144+
testUtils.VerifyBlockSignature{
145+
Identity: testUtils.ClientIdentity(2),
146+
SignerIdentity: testUtils.ClientIdentity(1).Value(),
147+
Cid: "bafyreicwhd5s762awsrx6eowwqkkfpq7r5nnjosiru7blgaxo32wx6enp4",
148+
ExpectedError: "not authorized to perform operation",
149+
},
150+
151+
// This should work as the identity is authorized.
152+
testUtils.VerifyBlockSignature{
153+
Identity: testUtils.ClientIdentity(1),
154+
SignerIdentity: testUtils.ClientIdentity(1).Value(),
155+
Cid: "bafyreicwhd5s762awsrx6eowwqkkfpq7r5nnjosiru7blgaxo32wx6enp4",
156+
ExpectedError: "could not find",
157+
},
158+
},
159+
}
160+
161+
testUtils.ExecuteTestCase(t, test)
162+
}
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
// Copyright 2025 Democratized Data Foundation
2+
//
3+
// Use of this software is governed by the Business Source License
4+
// included in the file licenses/BSL.txt.
5+
//
6+
// As of the Change Date specified in that file, in accordance with
7+
// the Business Source License, use of this software will be governed
8+
// by the Apache License, Version 2.0, included in the file
9+
// licenses/APL.txt.
10+
11+
package test_acp_aac
12+
13+
import (
14+
"testing"
15+
16+
"github.com/sourcenetwork/immutable"
17+
18+
testUtils "github.com/sourcenetwork/defradb/tests/integration"
19+
)
20+
21+
func TestAAC_GatesVerifySignature_AllowIfAuthorizedElseError(t *testing.T) {
22+
test := testUtils.TestCase{
23+
Description: "admin acp correctly gates verify signature operation, allow if authorized, otherwise error",
24+
EnableSigning: true,
25+
SupportedClientTypes: immutable.Some(
26+
[]testUtils.ClientType{
27+
// Default signer can be only tested with HTTP and CLI clients, because with Go client
28+
// when providing an identity, it includes the private key.
29+
testUtils.HTTPClientType,
30+
testUtils.CLIClientType,
31+
},
32+
),
33+
Actions: []any{
34+
// Starting with ACC, so only authorized user(s) can perform operations from here on out.
35+
testUtils.Close{},
36+
testUtils.Start{
37+
Identity: testUtils.ClientIdentity(1),
38+
EnableAAC: true,
39+
},
40+
// Note: Doing setup steps after starting with aac enabled, otherwise the in-memory tests
41+
// will loose setup state when the restart happens (i.e. the restart that started aac).
42+
testUtils.SchemaUpdate{
43+
Identity: testUtils.ClientIdentity(1),
44+
Schema: `
45+
type Users {
46+
name: String
47+
age: Int
48+
}`,
49+
},
50+
testUtils.CreateDoc{
51+
Identity: testUtils.ClientIdentity(1),
52+
DocMap: map[string]any{
53+
"name": "John",
54+
"age": 21,
55+
},
56+
},
57+
// Note: Setup is now done, the test code that follows is what we want to assert.
58+
59+
// We haven't authorized non-identities. So, this should error.
60+
testUtils.VerifyBlockSignature{
61+
Identity: testUtils.NoIdentity(),
62+
SignerIdentity: testUtils.NodeIdentity(0).Value(),
63+
Cid: "bafyreicwhd5s762awsrx6eowwqkkfpq7r5nnjosiru7blgaxo32wx6enp4",
64+
ExpectedError: "not authorized to perform operation",
65+
},
66+
67+
// Wrong user/identity will also not be authorized.
68+
testUtils.VerifyBlockSignature{
69+
Identity: testUtils.ClientIdentity(2),
70+
SignerIdentity: testUtils.NodeIdentity(0).Value(),
71+
Cid: "bafyreicwhd5s762awsrx6eowwqkkfpq7r5nnjosiru7blgaxo32wx6enp4",
72+
ExpectedError: "not authorized to perform operation",
73+
},
74+
75+
// This should work as the identity is authorized.
76+
testUtils.VerifyBlockSignature{
77+
Identity: testUtils.ClientIdentity(1),
78+
SignerIdentity: testUtils.NodeIdentity(0).Value(),
79+
Cid: "bafyreicwhd5s762awsrx6eowwqkkfpq7r5nnjosiru7blgaxo32wx6enp4",
80+
},
81+
},
82+
}
83+
84+
testUtils.ExecuteTestCase(t, test)
85+
}
86+
87+
func TestAAC_GatesVerifySignatureGo_AllowIfAuthorizedElseError(t *testing.T) {
88+
test := testUtils.TestCase{
89+
Description: "admin acp correctly gates verify signature operation (go client), allow if authorized, otherwise error",
90+
EnableSigning: true,
91+
SupportedClientTypes: immutable.Some(
92+
[]testUtils.ClientType{
93+
// Creating of signed documents over HTTP is not supported yet, because signing
94+
// requires a private key which we do not pass over HTTP.
95+
testUtils.GoClientType,
96+
},
97+
),
98+
Actions: []any{
99+
// Starting with ACC, so only authorized user(s) can perform operations from here on out.
100+
testUtils.Close{},
101+
testUtils.Start{
102+
Identity: testUtils.ClientIdentity(1),
103+
EnableAAC: true,
104+
},
105+
// Note: Doing setup steps after starting with aac enabled, otherwise the in-memory tests
106+
// will loose setup state when the restart happens (i.e. the restart that started aac).
107+
testUtils.SchemaUpdate{
108+
Identity: testUtils.ClientIdentity(1),
109+
Schema: `
110+
type Users {
111+
name: String
112+
age: Int
113+
}`,
114+
},
115+
testUtils.CreateDoc{
116+
Identity: testUtils.ClientIdentity(1),
117+
DocMap: map[string]any{
118+
"name": "John",
119+
"age": 21,
120+
},
121+
},
122+
// Note: Setup is now done, the test code that follows is what we want to assert.
123+
124+
// We haven't authorized non-identities. So, this should error.
125+
testUtils.VerifyBlockSignature{
126+
Identity: testUtils.NoIdentity(),
127+
SignerIdentity: testUtils.ClientIdentity(1).Value(),
128+
Cid: "bafyreicwhd5s762awsrx6eowwqkkfpq7r5nnjosiru7blgaxo32wx6enp4",
129+
ExpectedError: "not authorized to perform operation",
130+
},
131+
132+
// Wrong user/identity will also not be authorized.
133+
testUtils.VerifyBlockSignature{
134+
Identity: testUtils.ClientIdentity(2),
135+
SignerIdentity: testUtils.ClientIdentity(1).Value(),
136+
Cid: "bafyreicwhd5s762awsrx6eowwqkkfpq7r5nnjosiru7blgaxo32wx6enp4",
137+
ExpectedError: "not authorized to perform operation",
138+
},
139+
140+
// This should work as the identity is authorized.
141+
testUtils.VerifyBlockSignature{
142+
Identity: testUtils.ClientIdentity(1),
143+
SignerIdentity: testUtils.ClientIdentity(1).Value(),
144+
Cid: "bafyreicwhd5s762awsrx6eowwqkkfpq7r5nnjosiru7blgaxo32wx6enp4",
145+
ExpectedError: "could not find",
146+
},
147+
},
148+
}
149+
150+
testUtils.ExecuteTestCase(t, test)
151+
}

tests/integration/test_case.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -932,6 +932,8 @@ type VerifyBlockSignature struct {
932932
//
933933
// Use `ClientIdentity` to create a client identity and `NodeIdentity` to create a node identity.
934934
// Default value is `NoIdentity()`.
935+
//
936+
// If admin acp is enabled, identity will be used to check if this operation can be performed.
935937
Identity immutable.Option[Identity]
936938

937939
// The identity of the author of the block to verify the signature of.

0 commit comments

Comments
 (0)