Skip to content

Commit f7f489d

Browse files
committed
session: add a new session token v2
Session Token v2 solves the delegation, power of attorney, and chain-of-trust problems. It enables: - Account-based authority (direct or NNS-based indirect) - Multi-account subjects (multiple entities can use same token) - Multi-verb operations (GET, PUT, DELETE in single token) - Delegation chains (verifiable like X.509 certificates) - Indirect accounts (NeoFS Name Service resolution) Refs #241. Signed-off-by: Andrey Butusov <andrey@nspcc.io>
1 parent 2fb0e58 commit f7f489d

File tree

2 files changed

+252
-16
lines changed

2 files changed

+252
-16
lines changed

proto-docs/session.md

Lines changed: 104 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,20 @@
1818

1919
- Messages
2020
- [ContainerSessionContext](#neo.fs.v2.session.ContainerSessionContext)
21+
- [DelegationInfo](#neo.fs.v2.session.DelegationInfo)
2122
- [ObjectSessionContext](#neo.fs.v2.session.ObjectSessionContext)
2223
- [ObjectSessionContext.Target](#neo.fs.v2.session.ObjectSessionContext.Target)
2324
- [RequestMetaHeader](#neo.fs.v2.session.RequestMetaHeader)
2425
- [RequestVerificationHeader](#neo.fs.v2.session.RequestVerificationHeader)
2526
- [ResponseMetaHeader](#neo.fs.v2.session.ResponseMetaHeader)
2627
- [ResponseVerificationHeader](#neo.fs.v2.session.ResponseVerificationHeader)
28+
- [SessionContextV2](#neo.fs.v2.session.SessionContextV2)
2729
- [SessionToken](#neo.fs.v2.session.SessionToken)
2830
- [SessionToken.Body](#neo.fs.v2.session.SessionToken.Body)
29-
- [SessionToken.Body.TokenLifetime](#neo.fs.v2.session.SessionToken.Body.TokenLifetime)
31+
- [SessionTokenV2](#neo.fs.v2.session.SessionTokenV2)
32+
- [SessionTokenV2.Body](#neo.fs.v2.session.SessionTokenV2.Body)
33+
- [Target](#neo.fs.v2.session.Target)
34+
- [TokenLifetime](#neo.fs.v2.session.TokenLifetime)
3035
- [XHeader](#neo.fs.v2.session.XHeader)
3136

3237

@@ -147,6 +152,21 @@ Context information for Session Tokens related to ContainerService requests.
147152
| container_id | [neo.fs.v2.refs.ContainerID](#neo.fs.v2.refs.ContainerID) | | Particular container to which the action applies. Ignored if wildcard flag is set. |
148153

149154

155+
<a name="neo.fs.v2.session.DelegationInfo"></a>
156+
157+
### Message DelegationInfo
158+
DelegationInfo represents a single delegation in a chain of trust.
159+
160+
161+
| Field | Type | Label | Description |
162+
| ----- | ---- | ----- | ----------- |
163+
| issuer | [Target](#neo.fs.v2.session.Target) | | Account that performed this delegation. |
164+
| subject | [Target](#neo.fs.v2.session.Target) | | Account that received the delegation. |
165+
| timestamp | [int64](#int64) | | Unix timestamp when this delegation was created. |
166+
| verbs | [Verb](#neo.fs.v2.session.Verb) | repeated | List of verbs authorized by this delegation. |
167+
| signature | [neo.fs.v2.refs.Signature](#neo.fs.v2.refs.Signature) | | Signature of the issuer confirming this delegation record. The signature is created over the deterministic serialization of this DelegationInfo message excluding this field. |
168+
169+
150170
<a name="neo.fs.v2.session.ObjectSessionContext"></a>
151171

152172
### Message ObjectSessionContext
@@ -185,6 +205,7 @@ request meta headers are folded in matryoshka style.
185205
| ttl | [uint32](#uint32) | | Maximum number of intermediate nodes in the request route |
186206
| x_headers | [XHeader](#neo.fs.v2.session.XHeader) | repeated | Request X-Headers |
187207
| session_token | [SessionToken](#neo.fs.v2.session.SessionToken) | | Session token within which the request is sent |
208+
| session_token_v2 | [SessionTokenV2](#neo.fs.v2.session.SessionTokenV2) | | Session token v2 with delegation chain support. If both session_token and session_token_v2 are set, session_token_v2 takes precedence. |
188209
| bearer_token | [neo.fs.v2.acl.BearerToken](#neo.fs.v2.acl.BearerToken) | | `BearerToken` with eACL overrides for the request |
189210
| origin | [RequestMetaHeader](#neo.fs.v2.session.RequestMetaHeader) | | `RequestMetaHeader` of the origin request |
190211
| magic_number | [uint64](#uint64) | | NeoFS network magic. Must match the value for the network that the server belongs to. |
@@ -234,6 +255,19 @@ Verification info for the response signed by all intermediate nodes
234255
| origin | [ResponseVerificationHeader](#neo.fs.v2.session.ResponseVerificationHeader) | | Chain of previous hops signatures |
235256

236257

258+
<a name="neo.fs.v2.session.SessionContextV2"></a>
259+
260+
### Message SessionContextV2
261+
SessionContextV2 carries unified context for both ObjectService and ContainerService requests.
262+
263+
264+
| Field | Type | Label | Description |
265+
| ----- | ---- | ----- | ----------- |
266+
| container | [neo.fs.v2.refs.ContainerID](#neo.fs.v2.refs.ContainerID) | | Container where operation is allowed. For container operations, this is the container being operated on. For object operations, this is the container holding the objects. |
267+
| objects | [neo.fs.v2.refs.ObjectID](#neo.fs.v2.refs.ObjectID) | repeated | Specific objects where operation is allowed. Only relevant for object operations. Empty list means all objects in the container. |
268+
| verbs | [Verb](#neo.fs.v2.session.Verb) | repeated | Operations authorized for this context. |
269+
270+
237271
<a name="neo.fs.v2.session.SessionToken"></a>
238272

239273
### Message SessionToken
@@ -256,23 +290,65 @@ Session Token body
256290
| ----- | ---- | ----- | ----------- |
257291
| id | [bytes](#bytes) | | Token identifier is a valid UUIDv4 in binary form |
258292
| owner_id | [neo.fs.v2.refs.OwnerID](#neo.fs.v2.refs.OwnerID) | | Identifier of the session initiator |
259-
| lifetime | [SessionToken.Body.TokenLifetime](#neo.fs.v2.session.SessionToken.Body.TokenLifetime) | | Lifetime of the session |
293+
| lifetime | [TokenLifetime](#neo.fs.v2.session.TokenLifetime) | | Lifetime of the session |
260294
| session_key | [bytes](#bytes) | | Public key used in session |
261295
| object | [ObjectSessionContext](#neo.fs.v2.session.ObjectSessionContext) | | ObjectService session context |
262296
| container | [ContainerSessionContext](#neo.fs.v2.session.ContainerSessionContext) | | ContainerService session context |
263297

264298

265-
<a name="neo.fs.v2.session.SessionToken.Body.TokenLifetime"></a>
299+
<a name="neo.fs.v2.session.SessionTokenV2"></a>
300+
301+
### Message SessionTokenV2
302+
SessionTokenV2 represents NeoFS Session Token with delegation support.
303+
304+
305+
| Field | Type | Label | Description |
306+
| ----- | ---- | ----- | ----------- |
307+
| body | [SessionTokenV2.Body](#neo.fs.v2.session.SessionTokenV2.Body) | | Session token body. |
308+
| signature | [neo.fs.v2.refs.Signature](#neo.fs.v2.refs.Signature) | | Signature of the body by the issuer. |
309+
310+
311+
<a name="neo.fs.v2.session.SessionTokenV2.Body"></a>
312+
313+
### Message SessionTokenV2.Body
314+
Session Token body.
266315

267-
### Message SessionToken.Body.TokenLifetime
316+
317+
| Field | Type | Label | Description |
318+
| ----- | ---- | ----- | ----------- |
319+
| version | [uint32](#uint32) | | Token version. |
320+
| id | [bytes](#bytes) | | Token identifier (UUIDv4 in binary form). |
321+
| issuer | [Target](#neo.fs.v2.session.Target) | | Account that issued this token (who signed it). |
322+
| subjects | [Target](#neo.fs.v2.session.Target) | repeated | Accounts authorized by this token (who can use it). |
323+
| lifetime | [TokenLifetime](#neo.fs.v2.session.TokenLifetime) | | Lifetime of this token. |
324+
| contexts | [SessionContextV2](#neo.fs.v2.session.SessionContextV2) | repeated | Unified session contexts for both object and container operations. Multiple contexts allow authorization for different combinations. |
325+
| delegation_chain | [DelegationInfo](#neo.fs.v2.session.DelegationInfo) | repeated | Full history of authority delegation (chain of trust). |
326+
327+
328+
<a name="neo.fs.v2.session.Target"></a>
329+
330+
### Message Target
331+
Target account for SessionTokenV2.
332+
It can be either direct (OwnerID) or indirect (NNS domain).
333+
334+
335+
| Field | Type | Label | Description |
336+
| ----- | ---- | ----- | ----------- |
337+
| owner_id | [neo.fs.v2.refs.OwnerID](#neo.fs.v2.refs.OwnerID) | | Direct account reference via OwnerID (hash of verification script). |
338+
| nns_name | [string](#string) | | Indirect account reference via NeoFS Name Service. NNS name is a domain name that resolves to an OwnerID through the NeoFS Name Service. The name must be a valid DNS-like domain name (e.g., "example.neofs") that is registered in the NNS contract on the Neo blockchain. The NNS record should contain a string record with the corresponding OwnerID value. |
339+
340+
341+
<a name="neo.fs.v2.session.TokenLifetime"></a>
342+
343+
### Message TokenLifetime
268344
Lifetime parameters of the token. Field names taken from rfc7519.
269345

270346

271347
| Field | Type | Label | Description |
272348
| ----- | ---- | ----- | ----------- |
273349
| exp | [uint64](#uint64) | | Expiration epoch, the last epoch when token is valid. |
274350
| nbf | [uint64](#uint64) | | Not valid before epoch, the first epoch when token is valid. |
275-
| iat | [uint64](#uint64) | | Issued at Epoch |
351+
| iat | [uint64](#uint64) | | Issued at epoch. |
276352

277353

278354
<a name="neo.fs.v2.session.XHeader"></a>
@@ -338,6 +414,29 @@ Object request verbs
338414
| RANGEHASH | 7 | Refers to object.GetRangeHash RPC call |
339415

340416

417+
418+
<a name="neo.fs.v2.session.Verb"></a>
419+
420+
### Verb
421+
Verb represents all possible operations in NeoFS that can be authorized
422+
via session tokens or delegation chains. This enum covers both object and
423+
container service operations.
424+
425+
| Name | Number | Description |
426+
| ---- | ------ | ----------- |
427+
| VERB_UNSPECIFIED | 0 | Unknown verb |
428+
| OBJECT_PUT | 1 | Refers to object.Put RPC call |
429+
| OBJECT_GET | 2 | Refers to object.Get RPC call |
430+
| OBJECT_HEAD | 3 | Refers to object.Head RPC call |
431+
| OBJECT_SEARCH | 4 | Refers to object.Search RPC call |
432+
| OBJECT_DELETE | 5 | Refers to object.Delete RPC call |
433+
| OBJECT_RANGE | 6 | Refers to object.GetRange RPC call |
434+
| OBJECT_RANGEHASH | 7 | Refers to object.GetRangeHash RPC call |
435+
| CONTAINER_PUT | 8 | Refers to container.Put RPC call |
436+
| CONTAINER_DELETE | 9 | Refers to container.Delete RPC call |
437+
| CONTAINER_SETEACL | 10 | Refers to container.SetExtendedACL RPC call |
438+
439+
341440
<!-- end enums -->
342441

343442

session/types.proto

Lines changed: 148 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,48 @@ import "status/types.proto";
99
option csharp_namespace = "Neo.FileStorage.API.Session";
1010
option go_package = "github.com/nspcc-dev/neofs-sdk-go/proto/session";
1111

12+
// Verb represents all possible operations in NeoFS that can be authorized
13+
// via session tokens or delegation chains. This enum covers both object and
14+
// container service operations.
15+
enum Verb {
16+
// Unknown verb
17+
VERB_UNSPECIFIED = 0;
18+
19+
// Object operations
20+
21+
// Refers to object.Put RPC call
22+
OBJECT_PUT = 1;
23+
24+
// Refers to object.Get RPC call
25+
OBJECT_GET = 2;
26+
27+
// Refers to object.Head RPC call
28+
OBJECT_HEAD = 3;
29+
30+
// Refers to object.Search RPC call
31+
OBJECT_SEARCH = 4;
32+
33+
// Refers to object.Delete RPC call
34+
OBJECT_DELETE = 5;
35+
36+
// Refers to object.GetRange RPC call
37+
OBJECT_RANGE = 6;
38+
39+
// Refers to object.GetRangeHash RPC call
40+
OBJECT_RANGEHASH = 7;
41+
42+
// Container operations
43+
44+
// Refers to container.Put RPC call
45+
CONTAINER_PUT = 8;
46+
47+
// Refers to container.Delete RPC call
48+
CONTAINER_DELETE = 9;
49+
50+
// Refers to container.SetExtendedACL RPC call
51+
CONTAINER_SETEACL = 10;
52+
}
53+
1254
// Context information for Session Tokens related to ObjectService requests
1355
message ObjectSessionContext {
1456
// Object request verbs
@@ -85,6 +127,18 @@ message ContainerSessionContext {
85127
refs.ContainerID container_id = 3 [json_name = "containerID"];
86128
}
87129

130+
// Lifetime parameters of the token. Field names taken from rfc7519.
131+
message TokenLifetime {
132+
// Expiration epoch, the last epoch when token is valid.
133+
uint64 exp = 1 [json_name = "exp"];
134+
135+
// Not valid before epoch, the first epoch when token is valid.
136+
uint64 nbf = 2 [json_name = "nbf"];
137+
138+
// Issued at epoch.
139+
uint64 iat = 3 [json_name = "iat"];
140+
}
141+
88142
// NeoFS Session Token.
89143
message SessionToken {
90144
// Session Token body
@@ -95,17 +149,6 @@ message SessionToken {
95149
// Identifier of the session initiator
96150
neo.fs.v2.refs.OwnerID owner_id = 2 [json_name = "ownerID"];
97151

98-
// Lifetime parameters of the token. Field names taken from rfc7519.
99-
message TokenLifetime {
100-
// Expiration epoch, the last epoch when token is valid.
101-
uint64 exp = 1 [json_name = "exp"];
102-
103-
// Not valid before epoch, the first epoch when token is valid.
104-
uint64 nbf = 2 [json_name = "nbf"];
105-
106-
// Issued at Epoch
107-
uint64 iat = 3 [json_name = "iat"];
108-
}
109152
// Lifetime of the session
110153
TokenLifetime lifetime = 3 [json_name = "lifetime"];
111154

@@ -175,6 +218,10 @@ message RequestMetaHeader {
175218
// Session token within which the request is sent
176219
SessionToken session_token = 5 [json_name = "sessionToken"];
177220

221+
// Session token v2 with delegation chain support.
222+
// If both session_token and session_token_v2 are set, session_token_v2 takes precedence.
223+
SessionTokenV2 session_token_v2 = 9 [json_name = "sessionTokenV2"];
224+
178225
// `BearerToken` with eACL overrides for the request
179226
neo.fs.v2.acl.BearerToken bearer_token = 6 [json_name = "bearerToken"];
180227

@@ -232,3 +279,93 @@ message ResponseVerificationHeader {
232279
// Chain of previous hops signatures
233280
ResponseVerificationHeader origin = 4 [json_name = "origin"];
234281
}
282+
283+
// Session Token v2
284+
285+
// Target account for SessionTokenV2.
286+
// It can be either direct (OwnerID) or indirect (NNS domain).
287+
message Target {
288+
// Account identifier.
289+
oneof identifier {
290+
// Direct account reference via OwnerID (hash of verification script).
291+
neo.fs.v2.refs.OwnerID owner_id = 1 [json_name = "ownerID"];
292+
293+
// Indirect account reference via NeoFS Name Service.
294+
// NNS name is a domain name that resolves to an OwnerID through the
295+
// NeoFS Name Service. The name must be a valid DNS-like domain name
296+
// (e.g., "example.neofs") that is registered in the NNS contract on
297+
// the Neo blockchain. The NNS record should contain a string record with
298+
// the corresponding OwnerID value.
299+
string nns_name = 2 [json_name = "nnsName"];
300+
}
301+
}
302+
303+
// DelegationInfo represents a single delegation in a chain of trust.
304+
message DelegationInfo {
305+
// Account that performed this delegation.
306+
Target issuer = 1 [json_name = "issuer"];
307+
308+
// Account that received the delegation.
309+
Target subject = 2 [json_name = "subject"];
310+
311+
// Unix timestamp when this delegation was created.
312+
int64 timestamp = 3 [json_name = "timestamp"];
313+
314+
// List of verbs authorized by this delegation.
315+
repeated Verb verbs = 4 [json_name = "verbs"];
316+
317+
// Signature of the issuer confirming this delegation record.
318+
// The signature is created over the deterministic serialization
319+
// of this DelegationInfo message excluding this field.
320+
neo.fs.v2.refs.Signature signature = 5 [json_name = "signature"];
321+
}
322+
323+
// SessionContextV2 carries unified context for both ObjectService and ContainerService requests.
324+
message SessionContextV2 {
325+
// Container where operation is allowed.
326+
// For container operations, this is the container being operated on.
327+
// For object operations, this is the container holding the objects.
328+
neo.fs.v2.refs.ContainerID container = 1 [json_name = "container"];
329+
330+
// Specific objects where operation is allowed.
331+
// Only relevant for object operations.
332+
// Empty list means all objects in the container.
333+
repeated neo.fs.v2.refs.ObjectID objects = 2 [json_name = "objects"];
334+
335+
// Operations authorized for this context.
336+
repeated Verb verbs = 3 [json_name = "verbs"];
337+
}
338+
339+
// SessionTokenV2 represents NeoFS Session Token with delegation support.
340+
message SessionTokenV2 {
341+
// Session Token body.
342+
message Body {
343+
// Token version.
344+
uint32 version = 1 [json_name = "version"];
345+
346+
// Token identifier (UUIDv4 in binary form).
347+
bytes id = 2 [json_name = "id"];
348+
349+
// Account that issued this token (who signed it).
350+
Target issuer = 3 [json_name = "issuer"];
351+
352+
// Accounts authorized by this token (who can use it).
353+
repeated Target subjects = 4 [json_name = "subjects"];
354+
355+
// Lifetime of this token.
356+
TokenLifetime lifetime = 5 [json_name = "lifetime"];
357+
358+
// Unified session contexts for both object and container operations.
359+
// Multiple contexts allow authorization for different combinations.
360+
repeated SessionContextV2 contexts = 6 [json_name = "contexts"];
361+
362+
// Full history of authority delegation (chain of trust).
363+
repeated DelegationInfo delegation_chain = 7 [json_name = "delegationChain"];
364+
}
365+
366+
// Session token body.
367+
Body body = 1 [json_name = "body"];
368+
369+
// Signature of the body by the issuer.
370+
neo.fs.v2.refs.Signature signature = 2 [json_name = "signature"];
371+
}

0 commit comments

Comments
 (0)