aboutsummaryrefslogtreecommitdiff
path: root/crates/secd/proto/authzed/api/v1/permission_service.proto
blob: 859d0d07d56b25e0683a63cbe6a205b6b27471bc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
syntax = "proto3";
package authzed.api.v1;

option go_package = "github.com/authzed/authzed-go/proto/authzed/api/v1";
option java_package = "com.authzed.api.v1";

import "google/protobuf/struct.proto";
import "google/api/annotations.proto";
import "validate/validate.proto";

import "authzed/api/v1/core.proto";

// PermissionsService implements a set of RPCs that perform operations on
// relationships and permissions.
service PermissionsService {
  // ReadRelationships reads a set of the relationships matching one or more
  // filters.
  rpc ReadRelationships(ReadRelationshipsRequest)
    returns (stream ReadRelationshipsResponse) {
      option (google.api.http) = {
        post: "/v1/relationships/read"
        body: "*"
      };
  }

  // WriteRelationships atomically writes and/or deletes a set of specified
  // relationships. An optional set of preconditions can be provided that must
  // be satisfied for the operation to commit.
  rpc WriteRelationships(WriteRelationshipsRequest)
    returns (WriteRelationshipsResponse) {
      option (google.api.http) = {
        post: "/v1/relationships/write"
        body: "*"
      };
    }

  // DeleteRelationships atomically bulk deletes all relationships matching the
  // provided filter. If no relationships match, none will be deleted and the
  // operation will succeed. An optional set of preconditions can be provided that must
  // be satisfied for the operation to commit.
  rpc DeleteRelationships(DeleteRelationshipsRequest)
    returns (DeleteRelationshipsResponse) {
      option (google.api.http) = {
        post: "/v1/relationships/delete"
        body: "*"
      };
    }

  // CheckPermission determines for a given resource whether a subject computes
  // to having a permission or is a direct member of a particular relation.
  rpc CheckPermission(CheckPermissionRequest)
    returns (CheckPermissionResponse) {
      option (google.api.http) = {
        post: "/v1/permissions/check"
        body: "*"
      };
    }

  // ExpandPermissionTree reveals the graph structure for a resource's
  // permission or relation. This RPC does not recurse infinitely deep and may
  // require multiple calls to fully unnest a deeply nested graph.
  rpc ExpandPermissionTree(ExpandPermissionTreeRequest)
    returns (ExpandPermissionTreeResponse) {
      option (google.api.http) = {
        post: "/v1/permissions/expand"
        body: "*"
      };
    }

  // LookupResources returns all the resources of a given type that a subject
  // can access whether via a computed permission or relation membership.
  rpc LookupResources(LookupResourcesRequest)
    returns (stream LookupResourcesResponse) {
      option (google.api.http) = {
        post: "/v1/permissions/resources"
        body: "*"
      };
    }

  // LookupSubjects returns all the subjects of a given type that
  // have access whether via a computed permission or relation membership.
  rpc LookupSubjects(LookupSubjectsRequest)
    returns (stream LookupSubjectsResponse) {
      option (google.api.http) = {
        post: "/v1/permissions/subjects"
        body: "*"
      };
    }
}

// Consistency will define how a request is handled by the backend.
// By defining a consistency requirement, and a token at which those
// requirements should be applied, where applicable.
message Consistency {
  oneof requirement {
    option (validate.required) = true;

    // minimize_latency indicates that the latency for the call should be
    // minimized by having the system select the fastest snapshot available.
    bool minimize_latency = 1 [ (validate.rules).bool.const = true ];

    // at_least_as_fresh indicates that all data used in the API call must be
    // *at least as fresh* as that found in the ZedToken; more recent data might
    // be used if available or faster.
    ZedToken at_least_as_fresh = 2;

    // at_exact_snapshot indicates that all data used in the API call must be
    // *at the given* snapshot in time; if the snapshot is no longer available,
    // an error will be returned to the caller.
    ZedToken at_exact_snapshot = 3;

    // fully_consistent indicates that all data used in the API call *must* be
    // at the most recent snapshot found.
    //
    // NOTE: using this method can be *quite slow*, so unless there is a need to
    // do so, it is recommended to use `at_least_as_fresh` with a stored
    // ZedToken.
    bool fully_consistent = 4 [ (validate.rules).bool.const = true ];
  }
}

// RelationshipFilter is a collection of filters which when applied to a
// relationship will return relationships that have exactly matching fields.
//
// resource_type is required. All other fields are optional and if left
// unspecified will not filter relationships.
message RelationshipFilter {
  string resource_type = 1 [ (validate.rules).string = {
    pattern : "^([a-z][a-z0-9_]{1,61}[a-z0-9]/)?[a-z][a-z0-9_]{1,62}[a-z0-9]$",
    max_bytes : 128,
  } ];

  string optional_resource_id = 2 [ (validate.rules).string = {
    pattern : "^([a-zA-Z0-9_][a-zA-Z0-9/_|-]{0,127})?$",
    max_bytes : 128,
  } ];

  string optional_relation = 3 [ (validate.rules).string = {
    pattern : "^([a-z][a-z0-9_]{1,62}[a-z0-9])?$",
    max_bytes : 64,
  } ];

  SubjectFilter optional_subject_filter = 4;
}

// SubjectFilter specifies a filter on the subject of a relationship.
//
// subject_type is required and all other fields are optional, and will not
// impose any additional requirements if left unspecified.
message SubjectFilter {
  message RelationFilter {
    string relation = 1 [ (validate.rules).string = {
      pattern : "^([a-z][a-z0-9_]{1,62}[a-z0-9])?$",
      max_bytes : 64,
    } ];
  }

  string subject_type = 1 [ (validate.rules).string = {
    pattern : "^([a-z][a-z0-9_]{1,61}[a-z0-9]/)?[a-z][a-z0-9_]{1,62}[a-z0-9]$",
    max_bytes : 128,
  } ];

  string optional_subject_id = 2 [ (validate.rules).string = {
    pattern : "^(([a-zA-Z0-9_][a-zA-Z0-9/_|-]{0,127})|\\*)?$",
    max_bytes : 128,
  } ];

  RelationFilter optional_relation = 3;
}

// ReadRelationshipsRequest specifies one or more filters used to read matching
// relationships within the system.
message ReadRelationshipsRequest {
  Consistency consistency = 1;
  RelationshipFilter relationship_filter = 2
      [ (validate.rules).message.required = true ];
}

// ReadRelationshipsResponse contains a Relationship found that matches the
// specified relationship filter(s). A instance of this response message will
// be streamed to the client for each relationship found.
message ReadRelationshipsResponse {
  ZedToken read_at = 1 [ (validate.rules).message.required = true ];
  Relationship relationship = 2 [ (validate.rules).message.required = true ];
}

// Precondition specifies how and the existence or absence of certain
// relationships as expressed through the accompanying filter should affect
// whether or not the operation proceeds.
//
// MUST_NOT_MATCH will fail the parent request if any relationships match the
// relationships filter.
// MUST_MATCH will fail the parent request if there are no
// relationships that match the filter.
message Precondition {
  enum Operation {
    OPERATION_UNSPECIFIED = 0;
    OPERATION_MUST_NOT_MATCH = 1;
    OPERATION_MUST_MATCH = 2;
  }

  Operation operation = 1 [ (validate.rules).enum = {defined_only: true, not_in: [0]} ];
  RelationshipFilter filter = 2 [ (validate.rules).message.required = true ];
}

// WriteRelationshipsRequest contains a list of Relationship mutations that
// should be applied to the service. If the optional_preconditions parameter
// is included, all of the specified preconditions must also be satisfied before
// the write will be committed.
message WriteRelationshipsRequest {
  repeated RelationshipUpdate updates = 1
      [ (validate.rules).repeated .items.message.required = true ];

  repeated Precondition optional_preconditions = 2
      [ (validate.rules).repeated .items.message.required =
            true ]; // To be bounded by configuration
}

message WriteRelationshipsResponse { ZedToken written_at = 1; }

// DeleteRelationshipsRequest specifies which Relationships should be deleted,
// requesting the delete of *ALL* relationships that match the specified
// filters. If the optional_preconditions parameter is included, all of the
// specified preconditions must also be satisfied before the delete will be
// executed.
message DeleteRelationshipsRequest {
  RelationshipFilter relationship_filter = 1
      [ (validate.rules).message.required = true ];

  repeated Precondition optional_preconditions = 2
      [ (validate.rules).repeated .items.message.required =
            true ]; // To be bounded by configuration
}

message DeleteRelationshipsResponse { ZedToken deleted_at = 1; }

// CheckPermissionRequest issues a check on whether a subject has a permission
// or is a member of a relation, on a specific resource.
message CheckPermissionRequest {
  Consistency consistency = 1;

  // resource is the resource on which to check the permission or relation.
  ObjectReference resource = 2 [ (validate.rules).message.required = true ];

  // permission is the name of the permission (or relation) on which to execute
  // the check.
  string permission = 3 [ (validate.rules).string = {
    pattern : "^([a-z][a-z0-9_]{1,62}[a-z0-9])?$",
    max_bytes : 64,
  } ];

  // subject is the subject that will be checked for the permission or relation.
  SubjectReference subject = 4 [ (validate.rules).message.required = true ];

  /** context consists of named values that are injected into the caveat evaluation context **/
  google.protobuf.Struct context = 5 [ (validate.rules).message.required = false ];
}

message CheckPermissionResponse {
  enum Permissionship {
    PERMISSIONSHIP_UNSPECIFIED = 0;
    PERMISSIONSHIP_NO_PERMISSION = 1;
    PERMISSIONSHIP_HAS_PERMISSION = 2;
    PERMISSIONSHIP_CONDITIONAL_PERMISSION = 3;
  }

  ZedToken checked_at = 1 [ (validate.rules).message.required = false ];

  // Permissionship communicates whether or not the subject has the requested
  // permission or has a relationship with the given resource, over the given
  // relation.
  //
  // This value will be authzed.api.v1.PERMISSIONSHIP_HAS_PERMISSION if the
  // requested subject is a member of the computed permission set or there
  // exists a relationship with the requested relation from the given resource
  // to the given subject.
  Permissionship permissionship = 2 [ (validate.rules).enum = {defined_only: true, not_in: [0]} ];

  // partial_caveat_info holds information of a partially-evaluated caveated response
  PartialCaveatInfo partial_caveat_info = 3 [ (validate.rules).message.required = false ];
}

// ExpandPermissionTreeRequest returns a tree representing the expansion of all
// relationships found accessible from a permission or relation on a particular
// resource.
//
// ExpandPermissionTreeRequest is typically used to determine the full set of
// subjects with a permission, along with the relationships that grant said
// access.
message ExpandPermissionTreeRequest {
  Consistency consistency = 1;

  // resource is the resource over which to run the expansion.
  ObjectReference resource = 2 [ (validate.rules).message.required = true ];

  // permission is the name of the permission or relation over which to run the
  // expansion for the resource.
  string permission = 3 [ (validate.rules).string = {
    pattern : "^([a-z][a-z0-9_]{1,62}[a-z0-9])?$",
    max_bytes : 64,
  } ];
}

message ExpandPermissionTreeResponse {
  ZedToken expanded_at = 1;

  // tree_root is a tree structure whose leaf nodes are subjects, and
  // intermediate nodes represent the various operations (union, intersection,
  // exclusion) to reach those subjects.
  PermissionRelationshipTree tree_root = 2;
}

// LookupResourcesRequest performs a lookup of all resources of a particular
// kind on which the subject has the specified permission or the relation in
// which the subject exists, streaming back the IDs of those resources.
message LookupResourcesRequest {
  Consistency consistency = 1;

  // resource_object_type is the type of resource object for which the IDs will
  // be returned.
  string resource_object_type = 2 [ (validate.rules).string = {
    pattern : "^([a-z][a-z0-9_]{1,61}[a-z0-9]/)?[a-z][a-z0-9_]{1,62}[a-z0-9]$",
    max_bytes : 128,
  } ];

  // permission is the name of the permission or relation for which the subject
  // must Check.
  string permission = 3 [ (validate.rules).string = {
    pattern : "^[a-z][a-z0-9_]{1,62}[a-z0-9]$",
    max_bytes : 64,
  } ];

  // subject is the subject with access to the resources.
  SubjectReference subject = 4 [ (validate.rules).message.required = true ];

  /** context consists of named values that are injected into the caveat evaluation context **/
  google.protobuf.Struct context = 5 [ (validate.rules).message.required = false ];
}

// LookupPermissionship represents whether a Lookup response was partially evaluated or not
enum LookupPermissionship {
  LOOKUP_PERMISSIONSHIP_UNSPECIFIED = 0;
  LOOKUP_PERMISSIONSHIP_HAS_PERMISSION = 1;
  LOOKUP_PERMISSIONSHIP_CONDITIONAL_PERMISSION = 2;
}

// LookupResourcesResponse contains a single matching resource object ID for the
// requested object type, permission, and subject.
message LookupResourcesResponse {
  ZedToken looked_up_at = 1;
  string resource_object_id = 2;

  // permissionship indicates whether the response was partially evaluated or not
  LookupPermissionship permissionship = 3 [ (validate.rules).enum = {defined_only: true, not_in: [0]} ];

  // partial_caveat_info holds information of a partially-evaluated caveated response
  PartialCaveatInfo partial_caveat_info = 4  [ (validate.rules).message.required = false ];
}

// LookupSubjectsRequest performs a lookup of all subjects of a particular
// kind for which the subject has the specified permission or the relation in
// which the subject exists, streaming back the IDs of those subjects.
message LookupSubjectsRequest {
  Consistency consistency = 1;

  // resource is the resource for which all matching subjects for the permission
  // or relation will be returned.
  ObjectReference resource = 2 [ (validate.rules).message.required = true ];

  // permission is the name of the permission (or relation) for which to find
  // the subjects.
  string permission = 3 [ (validate.rules).string = {
    pattern : "^([a-z][a-z0-9_]{1,62}[a-z0-9])?$",
    max_bytes : 64,
  } ];

  // subject_object_type is the type of subject object for which the IDs will
  // be returned.
  string subject_object_type = 4 [ (validate.rules).string = {
    pattern : "^([a-z][a-z0-9_]{1,61}[a-z0-9]/)?[a-z][a-z0-9_]{1,62}[a-z0-9]$",
    max_bytes : 128,
  } ];

  // optional_subject_relation is the optional relation for the subject.
  string optional_subject_relation = 5 [ (validate.rules).string = {
    pattern : "^([a-z][a-z0-9_]{1,62}[a-z0-9])?$",
    max_bytes : 64,
  } ];

  /** context consists of named values that are injected into the caveat evaluation context **/
  google.protobuf.Struct context = 6 [ (validate.rules).message.required = false ];
}

// LookupSubjectsResponse contains a single matching subject object ID for the
// requested subject object type on the permission or relation.
message LookupSubjectsResponse {
  ZedToken looked_up_at = 1;

  // subject_object_id is the Object ID of the subject found. May be a `*` if
  // a wildcard was found.
  // deprecated: use `subject`
  string subject_object_id = 2 [deprecated = true];

  // excluded_subject_ids are the Object IDs of the subjects excluded. This list
  // will only contain object IDs if `subject_object_id` is a wildcard (`*`) and
  // will only be populated if exclusions exist from the wildcard.
  // deprecated: use `excluded_subjects`
  repeated string excluded_subject_ids = 3 [deprecated = true];

  // permissionship indicates whether the response was partially evaluated or not
  // deprecated: use `subject.permissionship`
  LookupPermissionship permissionship = 4 [ deprecated = true, (validate.rules).enum = {defined_only: true, not_in: [0]} ];

  // partial_caveat_info holds information of a partially-evaluated caveated response
  // deprecated: use `subject.partial_caveat_info`
  PartialCaveatInfo partial_caveat_info = 5 [ deprecated = true, (validate.rules).message.required = false ];

  // subject is the subject found, along with its permissionship.
  ResolvedSubject subject = 6;

  // excluded_subjects are the subjects excluded. This list
  // will only contain subjects if `subject.subject_object_id` is a wildcard (`*`) and
  // will only be populated if exclusions exist from the wildcard.
  repeated ResolvedSubject excluded_subjects = 7;
}

// ResolvedSubject is a single subject resolved within LookupSubjects.
message ResolvedSubject {
  // subject_object_id is the Object ID of the subject found. May be a `*` if
  // a wildcard was found.
  string subject_object_id = 1;

  // permissionship indicates whether the response was partially evaluated or not
  LookupPermissionship permissionship = 2 [ (validate.rules).enum = {defined_only: true, not_in: [0]} ];

  // partial_caveat_info holds information of a partially-evaluated caveated response
  PartialCaveatInfo partial_caveat_info = 3 [ (validate.rules).message.required = false ];
}