Skip to content

Commit a4dfb59

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 a4dfb59

File tree

2 files changed

+260
-18
lines changed

2 files changed

+260
-18
lines changed

proto-docs/session.md

Lines changed: 106 additions & 7 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+
| subjects | [Target](#neo.fs.v2.session.Target) | repeated | Accounts that received the delegation. |
165+
| lifetime | [TokenLifetime](#neo.fs.v2.session.TokenLifetime) | | Lifetime of this delegation. Allows each delegation in the chain to have its own validity window. |
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+
| delegation_chain | [DelegationInfo](#neo.fs.v2.session.DelegationInfo) | repeated | DelegationInfo is a full history of authority delegation (chain of trust). Similar to X.509 certificate chains, each delegation entry is independently signed by its issuer. |
310+
311+
312+
<a name="neo.fs.v2.session.SessionTokenV2.Body"></a>
313+
314+
### Message SessionTokenV2.Body
315+
Session Token body.
266316

267-
### Message SessionToken.Body.TokenLifetime
317+
318+
| Field | Type | Label | Description |
319+
| ----- | ---- | ----- | ----------- |
320+
| version | [uint32](#uint32) | | Token version. |
321+
| id | [bytes](#bytes) | | Token identifier (UUIDv4 in binary form). |
322+
| issuer | [Target](#neo.fs.v2.session.Target) | | Account that issued this token (who signed it). |
323+
| subjects | [Target](#neo.fs.v2.session.Target) | repeated | Accounts authorized by this token (who can use it). |
324+
| lifetime | [TokenLifetime](#neo.fs.v2.session.TokenLifetime) | | Lifetime of this token. |
325+
| contexts | [SessionContextV2](#neo.fs.v2.session.SessionContextV2) | repeated | Unified session contexts for both object and container operations. Multiple contexts allow authorization for different combinations. |
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
| ----- | ---- | ----- | ----------- |
273-
| exp | [uint64](#uint64) | | Expiration epoch, the last epoch when token is valid. |
274-
| nbf | [uint64](#uint64) | | Not valid before epoch, the first epoch when token is valid. |
275-
| iat | [uint64](#uint64) | | Issued at Epoch |
349+
| exp | [uint64](#uint64) | | Expiration epoch, the last epoch when token is valid. For SessionTokenV2 this is the last valid Unix timestamp. |
350+
| nbf | [uint64](#uint64) | | Not valid before epoch, the first epoch when token is valid. For SessionTokenV2 this is the first valid Unix timestamp. |
351+
| iat | [uint64](#uint64) | | Issued at epoch. For SessionTokenV2 this is the Unix timestamp when the token was issued. |
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: 154 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,21 @@ 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+
// For SessionTokenV2 this is the last valid Unix timestamp.
134+
uint64 exp = 1 [json_name = "exp"];
135+
136+
// Not valid before epoch, the first epoch when token is valid.
137+
// For SessionTokenV2 this is the first valid Unix timestamp.
138+
uint64 nbf = 2 [json_name = "nbf"];
139+
140+
// Issued at epoch.
141+
// For SessionTokenV2 this is the Unix timestamp when the token was issued.
142+
uint64 iat = 3 [json_name = "iat"];
143+
}
144+
88145
// NeoFS Session Token.
89146
message SessionToken {
90147
// Session Token body
@@ -95,17 +152,6 @@ message SessionToken {
95152
// Identifier of the session initiator
96153
neo.fs.v2.refs.OwnerID owner_id = 2 [json_name = "ownerID"];
97154

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-
}
109155
// Lifetime of the session
110156
TokenLifetime lifetime = 3 [json_name = "lifetime"];
111157

@@ -175,6 +221,10 @@ message RequestMetaHeader {
175221
// Session token within which the request is sent
176222
SessionToken session_token = 5 [json_name = "sessionToken"];
177223

224+
// Session token v2 with delegation chain support.
225+
// If both session_token and session_token_v2 are set, session_token_v2 takes precedence.
226+
SessionTokenV2 session_token_v2 = 9 [json_name = "sessionTokenV2"];
227+
178228
// `BearerToken` with eACL overrides for the request
179229
neo.fs.v2.acl.BearerToken bearer_token = 6 [json_name = "bearerToken"];
180230

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

0 commit comments

Comments
 (0)