-
Notifications
You must be signed in to change notification settings - Fork 894
feat: Add initial AuthzQuerier implementation #5919
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
7d0fad4
efe7f93
923219a
f97ca2a
ad6ff52
0e3b9ff
feb7689
083bcf2
161842d
11983ab
ab9c049
04e32bc
21d0f97
76a490e
fa399d6
cb9a2c5
9aa7835
8f6265b
bfa91c1
13710c6
467646d
32c8af1
11ef507
b08fc44
69a6346
4967fe6
6a7b053
fc992cd
d599753
0ce75c6
357b05d
6bb2e1c
8a8ce06
300f6dc
9f7d276
d37379d
6cc14b4
2107b74
53f7a5d
44ca906
73655ab
0d6f6a0
32a9e12
85ff5f1
e152d5f
ef1deb5
4848481
b583a1e
75747f5
add77c6
4357a3c
9dbc6bf
c285f6f
58261fe
a4a2994
874e9da
d878e71
10ac765
e353c4d
db647ba
f45a170
b4beb38
d9d23b6
8780e4e
e6d5c2f
672b2e0
5a0e5a2
016c56d
e086e51
390a284
53fcf79
0add01a
6191561
e8ab762
837f66a
88d422f
a32b4f3
d3affdc
338e300
f5c4040
a7899cf
0da03c6
4415b6b
fb8973c
6763fbf
d1b948d
13a4fab
607e428
592a62b
102af8a
d2b1f41
b6afc2a
d1cfa73
b7cd5a5
f34c61b
e53d709
cb4d92f
13a8445
e1ce04e
7fde8fb
7ba3482
cf763cb
64e80fb
432a261
8134d1b
29e7c46
a37fead
2e435cf
792cbb6
1336e28
0923780
92f89ec
acae52b
764b0a0
0cee453
d1e3214
e799713
cbb4502
83a31cb
9010ad7
912c97a
a3f67bb
7d31209
2c906e5
5e92648
04cce68
712c0f4
8f92a77
3df9848
90a9d87
8b39d7e
a621743
2c002bd
cbd5cb4
6fed479
5928c37
46b8366
21a6f6a
d6810de
889b650
72ed503
94ff5ef
38a90de
c962897
62e3fa0
a0725b9
a4c4489
567cfa4
91910af
dce10b5
58b71f9
833bbc2
fcfdb4e
8858fd3
64e0f8c
9d6ab90
1821dcb
7c9f686
eda4e0a
073aa2c
4fe26e9
13f1c9f
ba172ea
509ebdc
802272b
57cde94
4daa878
4608462
2767264
fc3ae4b
bf653b6
ca68db2
f1f05cc
eb38c0d
b96bb21
0a061be
8295eb3
c2bc20e
3bd3e89
052c531
6aa55ac
72d0a4e
4c68562
fdfdd73
c902715
f5dbd3e
97ad3df
b369c99
03d42d3
69d1aa3
3861a43
9e7ff9a
9dc357e
ad6ad36
0985060
d4e1124
4e6b43f
22e1057
c5346ad
7a14b64
b89b430
21532a6
6a7970f
399241a
924ef9c
2cf0fb2
d1bb7cf
ef97e4b
951d74f
2cf1cad
a9f2581
832d91a
0ddee07
cc76887
002f354
039e1e2
b509b8f
524394f
f666e13
1a97843
4b292e2
bebe638
f99c778
84bc12f
c5e69fa
a93c2d5
f7023a4
035609b
bbe4f18
f0bbaaf
51a2dae
00955e0
2289f4d
106d58b
2724dfd
2c34f6d
c54afc5
d282e9c
7334046
3dbbc71
cd6096f
eb2497a
d2c7a1f
99fa810
1dfa287
57ab200
306c591
f39cee0
2ed5588
c09b077
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -54,6 +54,7 @@ func LogNotAuthorizedError(ctx context.Context, logger slog.Logger, err error) e | |
} | ||
} | ||
|
||
// insert is the same as insertWithReturn, but does not return the inserted object. | ||
func insert[ArgumentType any, | ||
Insert func(ctx context.Context, arg ArgumentType) error]( | ||
// Arguments | ||
|
@@ -69,6 +70,9 @@ func insert[ArgumentType any, | |
} | ||
} | ||
|
||
// insertWithReturn runs an rbac.ActionCreate on the rbac object argument before | ||
// running the insertFunc. The insertFunc is expected to return the object that | ||
// was inserted. | ||
func insertWithReturn[ObjectType any, ArgumentType any, | ||
Insert func(ctx context.Context, arg ArgumentType) (ObjectType, error)]( | ||
// Arguments | ||
|
@@ -130,9 +134,45 @@ func update[ObjectType rbac.Objecter, | |
return fetchAndExec(logger, authorizer, rbac.ActionUpdate, fetchFunc, updateExec) | ||
Emyrk marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
// authorizedFetchAndExecWithConverter uses authorizedFetchAndQueryWithConverter but | ||
// only cares about the error return type. SQL execs only return an error. | ||
// See authorizedFetchAndQueryWithConverter for more details. | ||
// fetch is a generic function that wraps a database | ||
// query function (returns an object and an error) with authorization. The | ||
// returned function has the same arguments as the database function. | ||
// | ||
// The database query function will **ALWAYS** hit the database, even if the | ||
// user cannot read the resource. This is because the resource details are | ||
// required to run a proper authorization check. | ||
func fetch[ArgumentType any, ObjectType rbac.Objecter, | ||
DatabaseFunc func(ctx context.Context, arg ArgumentType) (ObjectType, error)]( | ||
// Arguments | ||
logger slog.Logger, | ||
authorizer rbac.Authorizer, | ||
f DatabaseFunc) DatabaseFunc { | ||
return func(ctx context.Context, arg ArgumentType) (empty ObjectType, err error) { | ||
// Fetch the rbac subject | ||
act, ok := ActorFromContext(ctx) | ||
if !ok { | ||
return empty, NoActorError | ||
} | ||
|
||
// Fetch the database object | ||
object, err := f(ctx, arg) | ||
if err != nil { | ||
return empty, xerrors.Errorf("fetch object: %w", err) | ||
} | ||
|
||
// Authorize the action | ||
err = authorizer.Authorize(ctx, act, rbac.ActionRead, object.RBACObject()) | ||
if err != nil { | ||
return empty, LogNotAuthorizedError(ctx, logger, err) | ||
} | ||
|
||
return object, nil | ||
} | ||
} | ||
|
||
// fetchAndExec uses fetchAndQuery but only returns the error. The naming comes | ||
// from SQL 'exec' functions which only return an error. | ||
// See fetchAndQuery for more information. | ||
func fetchAndExec[ObjectType rbac.Objecter, | ||
ArgumentType any, | ||
Fetch func(ctx context.Context, arg ArgumentType) (ObjectType, error), | ||
|
@@ -152,6 +192,10 @@ func fetchAndExec[ObjectType rbac.Objecter, | |
} | ||
} | ||
|
||
// fetchAndQuery is a generic function that wraps a database fetch and query. | ||
// The fetch is used to know which rbac object the action should be asserted on | ||
// **before** the query runs. The returns from the fetch are only used to | ||
// assert rbac. The final return of this function comes from the Query function. | ||
func fetchAndQuery[ObjectType rbac.Objecter, ArgumentType any, | ||
Fetch func(ctx context.Context, arg ArgumentType) (ObjectType, error), | ||
Query func(ctx context.Context, arg ArgumentType) (ObjectType, error)]( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I still don't understand the difference between a fetch and a query. They have the same signature. The next method is called "fetch" and says, "fetch is a generic function that wraps a database query" suggesting that maybe they are interchangeable? This file is extremely abstract, so it is extremely important that we pick a consistent set of terms, define them tightly, and stick to the definitions. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The difference is a // fetchAndQuery is a generic function that wraps a database fetch and query.
// A query has potential side effects in the database (update, delete, etc).
// The fetch is used to know which rbac object the action should be asserted on
// **before** the query runs. The returns from the fetch are only used to
// assert rbac. The final return of this function comes from the Query function. |
||
|
@@ -184,42 +228,6 @@ func fetchAndQuery[ObjectType rbac.Objecter, ArgumentType any, | |
} | ||
} | ||
|
||
// fetch is a generic function that wraps a database | ||
// query function (returns an object and an error) with authorization. The | ||
// returned function has the same arguments as the database function. | ||
// | ||
// The database query function will **ALWAYS** hit the database, even if the | ||
// user cannot read the resource. This is because the resource details are | ||
// required to run a proper authorization check. | ||
func fetch[ArgumentType any, ObjectType rbac.Objecter, | ||
DatabaseFunc func(ctx context.Context, arg ArgumentType) (ObjectType, error)]( | ||
// Arguments | ||
logger slog.Logger, | ||
authorizer rbac.Authorizer, | ||
f DatabaseFunc) DatabaseFunc { | ||
return func(ctx context.Context, arg ArgumentType) (empty ObjectType, err error) { | ||
// Fetch the rbac subject | ||
act, ok := ActorFromContext(ctx) | ||
if !ok { | ||
return empty, NoActorError | ||
} | ||
|
||
// Fetch the database object | ||
object, err := f(ctx, arg) | ||
if err != nil { | ||
return empty, xerrors.Errorf("fetch object: %w", err) | ||
} | ||
|
||
// Authorize the action | ||
err = authorizer.Authorize(ctx, act, rbac.ActionRead, object.RBACObject()) | ||
if err != nil { | ||
return empty, LogNotAuthorizedError(ctx, logger, err) | ||
} | ||
|
||
return object, nil | ||
} | ||
} | ||
|
||
// fetchWithPostFilter is like fetch, but works with lists of objects. | ||
// SQL filters are much more optimal. | ||
func fetchWithPostFilter[ArgumentType any, ObjectType rbac.Objecter, | ||
|
Uh oh!
There was an error while loading. Please reload this page.