-
Notifications
You must be signed in to change notification settings - Fork 34
Expand file tree
/
Copy pathaccess.go
More file actions
140 lines (121 loc) · 5.46 KB
/
Copy pathaccess.go
File metadata and controls
140 lines (121 loc) · 5.46 KB
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
package kata
import (
"context"
"database/sql"
"errors"
)
// ErrAccessDenied is returned by an AccessController when a caller must not
// learn whether the requested resource exists.
var ErrAccessDenied = errors.New("kata: access denied")
// Principal is the authenticated identity supplied by an embedding host.
// Subject is a stable opaque identifier and also anchors lease ownership. Its
// exact bytes are significant; callers must supply the same canonical value
// on every request.
// Actor is the display snapshot Kata records on mutations instead of accepting
// an actor from request data.
type Principal struct {
Subject string
Actor string
}
// Capability is the product-neutral authority class an operation requires.
// Embedding hosts map these classes to their own roles and grants.
type Capability string
// Capability values form the stable authority vocabulary exposed to hosts.
const (
CapabilityRead Capability = "read"
CapabilityWrite Capability = "write"
CapabilityManage Capability = "manage"
CapabilityFederate Capability = "federate"
)
// OperationKind describes the domain boundary of a matched route. The values
// are owned by Kata so embedding hosts do not have to duplicate route policy.
type OperationKind string
// Operation kinds group routes by their data and administration boundary.
const (
OperationServiceRead OperationKind = "service_read"
OperationProjectRead OperationKind = "project_read"
OperationTaskRead OperationKind = "task_read"
OperationTaskMutation OperationKind = "task_mutation"
OperationTaskAdministration OperationKind = "task_administration"
OperationProjectAdministration OperationKind = "project_administration"
OperationTokenAdministration OperationKind = "token_administration"
OperationFederationRead OperationKind = "federation_read"
OperationFederationAdministration OperationKind = "federation_administration"
OperationFederationTransport OperationKind = "federation_transport"
OperationIntegrationAdministration OperationKind = "integration_administration"
)
// OperationPolicy is Kata's deny-by-default classification of one route.
// Mutation and LongLived let a host apply browser and resource controls without
// inferring behavior from an HTTP verb or operation name.
type OperationPolicy struct {
Kind OperationKind
Capability Capability
Mutation bool
LongLived bool
}
// Operation identifies the matched Kata HTTP operation without assigning any
// host-specific meaning to it.
type Operation struct {
ID string
Method string
Path string
PathParams map[string]string
Policy OperationPolicy
// ProjectIDs and ProjectUIDs identify every project whose data the
// operation may read or change. AllProjects is true when a global selector
// is used or when an operation can depend on projects that cannot be safely
// bounded before dispatch. Values are parsed and validated before
// authorization; cross-project operations include both sides.
ProjectIDs []int64
ProjectUIDs []string
AllProjects bool
}
// AccessRequest is the complete input to one host authorization decision.
type AccessRequest struct {
Principal Principal
Operation Operation
}
// AccessLease revalidates a host decision while a long-lived response is
// active. Revalidate must fail as soon as the principal or resource authority
// represented by the lease is no longer current.
type AccessLease interface {
Revalidate(context.Context) error
}
// Transaction is the narrow database/sql surface supplied to a transaction
// fence. Both SQLite and PostgreSQL transactions implement it.
type Transaction interface {
ExecContext(context.Context, string, ...any) (sql.Result, error)
QueryRowContext(context.Context, string, ...any) *sql.Row
}
// TransactionFence revalidates authority from inside the active storage
// transaction. Returning an error aborts and rolls back the domain mutation.
type TransactionFence func(context.Context, Transaction) error
// AccessDecision carries state needed after a request is admitted. Lease may
// be nil for bounded responses; long-lived operations require one.
type AccessDecision struct {
Lease AccessLease
// TransactionFence should be present on every successful decision. Kata
// invokes it when handling the operation begins a writable storage
// transaction, before the transaction's first domain write, and retains its
// database locks through commit or rollback.
TransactionFence TransactionFence
}
// AccessController makes host-owned authorization decisions for a mounted
// service. A request may be repeated with a larger, cumulative project scope
// when resolving a UID, link, or graph discovers another project, so
// implementations must make retry-safe decisions. Returning ErrAccessDenied
// produces a generic not-found response; other errors make only the mounted
// service temporarily unavailable.
type AccessController interface {
Authorize(context.Context, AccessRequest) (AccessDecision, error)
}
type principalContextKey struct{}
// WithPrincipal attaches a host-authenticated principal to an in-process
// request. It is intended for middleware immediately outside Service.Handler.
func WithPrincipal(ctx context.Context, principal Principal) context.Context {
return context.WithValue(ctx, principalContextKey{}, principal)
}
func principalFromContext(ctx context.Context) (Principal, bool) {
principal, ok := ctx.Value(principalContextKey{}).(Principal)
return principal, ok
}