Skip to content

Commit a55d2f4

Browse files
committed
PR(MAIN): Gate & Test - Verify Signature
1 parent 87f5b10 commit a55d2f4

5 files changed

Lines changed: 320 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
NodeSchemaPatchPerm
9696
NodePatchCollectionPerm
9797
NodeGetIdentityPerm
98+
NodeVerifySignaturePerm
9899
)
99100

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

127129
const NodeACPObject = "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.checkNodeAccess(ctx, acpTypes.NodeVerifySignaturePerm); err != nil {
33+
return err
34+
}
35+
3236
parsedCid, err := cid.Parse(blockCid)
3337
if err != nil {
3438
return err
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
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 TestNAC_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 NAC, so only authorized user(s) can perform operations from here on out.
57+
testUtils.Close{},
58+
testUtils.Start{
59+
Identity: testUtils.ClientIdentity(1),
60+
EnableNAC: 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 TestNAC_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 NAC, so only authorized user(s) can perform operations from here on out.
111+
testUtils.Close{},
112+
testUtils.Start{
113+
Identity: testUtils.ClientIdentity(1),
114+
EnableNAC: 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+
134+
// We haven't authorized non-identities. So, this should error.
135+
testUtils.VerifyBlockSignature{
136+
Identity: testUtils.NoIdentity(),
137+
SignerIdentity: testUtils.ClientIdentity(1).Value(),
138+
Cid: "bafyreicwhd5s762awsrx6eowwqkkfpq7r5nnjosiru7blgaxo32wx6enp4",
139+
ExpectedError: "not authorized to perform operation",
140+
},
141+
142+
// Wrong user/identity will also not be authorized.
143+
testUtils.VerifyBlockSignature{
144+
Identity: testUtils.ClientIdentity(2),
145+
SignerIdentity: testUtils.ClientIdentity(1).Value(),
146+
Cid: "bafyreicwhd5s762awsrx6eowwqkkfpq7r5nnjosiru7blgaxo32wx6enp4",
147+
ExpectedError: "not authorized to perform operation",
148+
},
149+
150+
// This should work as the identity is authorized.
151+
testUtils.VerifyBlockSignature{
152+
Identity: testUtils.ClientIdentity(1),
153+
SignerIdentity: testUtils.ClientIdentity(1).Value(),
154+
Cid: "bafyreicwhd5s762awsrx6eowwqkkfpq7r5nnjosiru7blgaxo32wx6enp4",
155+
ExpectedError: "could not find",
156+
},
157+
},
158+
}
159+
160+
testUtils.ExecuteTestCase(t, test)
161+
}
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
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 TestNAC_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 NAC, so only authorized user(s) can perform operations from here on out.
35+
testUtils.Close{},
36+
testUtils.Start{
37+
Identity: testUtils.ClientIdentity(1),
38+
EnableNAC: 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+
58+
// We haven't authorized non-identities. So, this should error.
59+
testUtils.VerifyBlockSignature{
60+
Identity: testUtils.NoIdentity(),
61+
SignerIdentity: testUtils.NodeIdentity(0).Value(),
62+
Cid: "bafyreicwhd5s762awsrx6eowwqkkfpq7r5nnjosiru7blgaxo32wx6enp4",
63+
ExpectedError: "not authorized to perform operation",
64+
},
65+
66+
// Wrong user/identity will also not be authorized.
67+
testUtils.VerifyBlockSignature{
68+
Identity: testUtils.ClientIdentity(2),
69+
SignerIdentity: testUtils.NodeIdentity(0).Value(),
70+
Cid: "bafyreicwhd5s762awsrx6eowwqkkfpq7r5nnjosiru7blgaxo32wx6enp4",
71+
ExpectedError: "not authorized to perform operation",
72+
},
73+
74+
// This should work as the identity is authorized.
75+
testUtils.VerifyBlockSignature{
76+
Identity: testUtils.ClientIdentity(1),
77+
SignerIdentity: testUtils.NodeIdentity(0).Value(),
78+
Cid: "bafyreicwhd5s762awsrx6eowwqkkfpq7r5nnjosiru7blgaxo32wx6enp4",
79+
},
80+
},
81+
}
82+
83+
testUtils.ExecuteTestCase(t, test)
84+
}
85+
86+
func TestNAC_GatesVerifySignatureGo_AllowIfAuthorizedElseError(t *testing.T) {
87+
test := testUtils.TestCase{
88+
Description: "admin acp correctly gates verify signature operation (go client), allow if authorized, otherwise error",
89+
EnableSigning: true,
90+
SupportedClientTypes: immutable.Some(
91+
[]testUtils.ClientType{
92+
// Creating of signed documents over HTTP is not supported yet, because signing
93+
// requires a private key which we do not pass over HTTP.
94+
testUtils.GoClientType,
95+
},
96+
),
97+
Actions: []any{
98+
// Starting with NAC, so only authorized user(s) can perform operations from here on out.
99+
testUtils.Close{},
100+
testUtils.Start{
101+
Identity: testUtils.ClientIdentity(1),
102+
EnableNAC: true,
103+
},
104+
// Note: Doing setup steps after starting with aac enabled, otherwise the in-memory tests
105+
// will loose setup state when the restart happens (i.e. the restart that started aac).
106+
testUtils.SchemaUpdate{
107+
Identity: testUtils.ClientIdentity(1),
108+
Schema: `
109+
type Users {
110+
name: String
111+
age: Int
112+
}`,
113+
},
114+
testUtils.CreateDoc{
115+
Identity: testUtils.ClientIdentity(1),
116+
DocMap: map[string]any{
117+
"name": "John",
118+
"age": 21,
119+
},
120+
},
121+
122+
// We haven't authorized non-identities. So, this should error.
123+
testUtils.VerifyBlockSignature{
124+
Identity: testUtils.NoIdentity(),
125+
SignerIdentity: testUtils.ClientIdentity(1).Value(),
126+
Cid: "bafyreicwhd5s762awsrx6eowwqkkfpq7r5nnjosiru7blgaxo32wx6enp4",
127+
ExpectedError: "not authorized to perform operation",
128+
},
129+
130+
// Wrong user/identity will also not be authorized.
131+
testUtils.VerifyBlockSignature{
132+
Identity: testUtils.ClientIdentity(2),
133+
SignerIdentity: testUtils.ClientIdentity(1).Value(),
134+
Cid: "bafyreicwhd5s762awsrx6eowwqkkfpq7r5nnjosiru7blgaxo32wx6enp4",
135+
ExpectedError: "not authorized to perform operation",
136+
},
137+
138+
// This should work as the identity is authorized.
139+
testUtils.VerifyBlockSignature{
140+
Identity: testUtils.ClientIdentity(1),
141+
SignerIdentity: testUtils.ClientIdentity(1).Value(),
142+
Cid: "bafyreicwhd5s762awsrx6eowwqkkfpq7r5nnjosiru7blgaxo32wx6enp4",
143+
ExpectedError: "could not find",
144+
},
145+
},
146+
}
147+
148+
testUtils.ExecuteTestCase(t, test)
149+
}

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 node 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)