chore: Implement standard rbac.Subject to be reused everywhere (#5881)

* chore: Implement standard rbac.Subject to be reused everywhere

An rbac subject is created in multiple spots because of the way we
expand roles, scopes, etc. This difference in use creates a list
of arguments which is unwieldy.

Use of the expander interface lets us conform to a single subject
in every case
This commit is contained in:
Steven Masley
2023-01-26 14:42:54 -06:00
committed by GitHub
parent 5c54d8b8cd
commit b0a16150a3
18 changed files with 465 additions and 371 deletions

View File

@ -52,11 +52,10 @@ func APIKey(r *http.Request) database.APIKey {
type userAuthKey struct{}
type Authorization struct {
ID uuid.UUID
Actor rbac.Subject
// Username is required for logging and human friendly related
// identification.
Username string
Roles rbac.RoleNames
Groups []string
Scope database.APIKeyScope
}
// UserAuthorizationOptional may return the roles and scope used for
@ -343,11 +342,13 @@ func ExtractAPIKey(cfg ExtractAPIKeyConfig) func(http.Handler) http.Handler {
ctx = context.WithValue(ctx, apiKeyContextKey{}, key)
ctx = context.WithValue(ctx, userAuthKey{}, Authorization{
ID: key.UserID,
Username: roles.Username,
Roles: roles.Roles,
Scope: key.Scope,
Groups: roles.Groups,
Actor: rbac.Subject{
ID: key.UserID.String(),
Roles: rbac.RoleNames(roles.Roles),
Groups: roles.Groups,
Scope: rbac.ScopeName(key.Scope),
},
})
next.ServeHTTP(rw, r.WithContext(ctx))

View File

@ -126,8 +126,8 @@ func TestExtractUserRoles(t *testing.T) {
)
rtr.Get("/", func(_ http.ResponseWriter, r *http.Request) {
roles := httpmw.UserAuthorization(r)
require.ElementsMatch(t, user.ID, roles.ID)
require.ElementsMatch(t, expRoles, roles.Roles)
require.Equal(t, user.ID.String(), roles.Actor.ID)
require.ElementsMatch(t, expRoles, roles.Actor.Roles.Names())
})
req := httptest.NewRequest("GET", "/", nil)

View File

@ -47,7 +47,7 @@ func RateLimit(count int, window time.Duration) func(http.Handler) http.Handler
// We avoid using rbac.Authorizer since rego is CPU-intensive
// and undermines the DoS-prevention goal of the rate limiter.
for _, role := range auth.Roles {
for _, role := range auth.Actor.SafeRoleNames() {
if role == rbac.RoleOwner() {
// HACK: use a random key each time to
// de facto disable rate limiting. The