Skip to content

Commit b509b8f

Browse files
committed
wip: dbauthz.WithAuthorizeSystemContext -> dbauthz.AsSystem()
1 parent 039e1e2 commit b509b8f

17 files changed

+155
-133
lines changed

coderd/autobuild/executor/lifecycle_executor.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import (
1313
"github.com/coder/coder/coderd/autobuild/schedule"
1414
"github.com/coder/coder/coderd/database"
1515
"github.com/coder/coder/coderd/database/dbauthz"
16-
"github.com/coder/coder/coderd/rbac"
1716
)
1817

1918
// Executor automatically starts or stops workspaces.
@@ -35,8 +34,8 @@ type Stats struct {
3534
// New returns a new autobuild executor.
3635
func New(ctx context.Context, db database.Store, log slog.Logger, tick <-chan time.Time) *Executor {
3736
le := &Executor{
38-
// Use an authorized context with an autostart system actor.
39-
ctx: dbauthz.WithAuthorizeSystemContext(ctx, rbac.RolesAutostartSystem()),
37+
// Use an authorized context
38+
ctx: dbauthz.AsSystem(ctx),
4039
db: db,
4140
tick: tick,
4241
log: log,

coderd/database/dbauthz/dbauthz.go

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -105,20 +105,56 @@ func ActorFromContext(ctx context.Context) (rbac.Subject, bool) {
105105
return a, ok
106106
}
107107

108-
func WithAuthorizeContext(ctx context.Context, actor rbac.Subject) context.Context {
109-
return context.WithValue(ctx, authContextKey{}, actor)
108+
// func WithAuthorizeContext(ctx context.Context, actor rbac.Subject) context.Context {
109+
// return context.WithValue(ctx, authContextKey{}, actor)
110+
// }
111+
112+
// func WithAuthorizeSystemContext(ctx context.Context, roles rbac.ExpandableRoles) context.Context {
113+
// // TODO: Add protections to search for user roles. If user roles are found,
114+
// // this should panic. That is a developer error that should be caught
115+
// // in unit tests.
116+
// return context.WithValue(ctx, authContextKey{}, rbac.Subject{
117+
// ID: uuid.Nil.String(),
118+
// Roles: roles,
119+
// Scope: rbac.ScopeAll,
120+
// Groups: []string{},
121+
// })
122+
// }
123+
124+
// AsSystem returns a context with a system actor. This is used for internal
125+
// system operations that do not require authorization.
126+
//
127+
// We trust you have received the usual lecture from the local System
128+
// Administrator. It usually boils down to these three things:
129+
// #1) Respect the privacy of others.
130+
// #2) Think before you type.
131+
// #3) With great power comes great responsibility.
132+
func AsSystem(ctx context.Context) context.Context {
133+
return context.WithValue(ctx, authContextKey{}, rbac.Subject{
134+
ID: uuid.Nil.String(),
135+
Roles: rbac.Roles([]rbac.Role{
136+
{
137+
Name: "system",
138+
DisplayName: "System",
139+
Site: []rbac.Permission{
140+
{
141+
ResourceType: rbac.ResourceWildcard.Type,
142+
Action: rbac.WildcardSymbol,
143+
},
144+
},
145+
Org: map[string][]rbac.Permission{},
146+
User: []rbac.Permission{},
147+
},
148+
}),
149+
},
150+
)
110151
}
111152

112-
func WithAuthorizeSystemContext(ctx context.Context, roles rbac.ExpandableRoles) context.Context {
113-
// TODO: Add protections to search for user roles. If user roles are found,
114-
// this should panic. That is a developer error that should be caught
115-
// in unit tests.
116-
return context.WithValue(ctx, authContextKey{}, rbac.Subject{
117-
ID: uuid.Nil.String(),
118-
Roles: roles,
119-
Scope: rbac.ScopeAll,
120-
Groups: []string{},
121-
})
153+
// As returns a context with the given actor stored in the context.
154+
// This is used for cases where the actor touching the database is not the
155+
// actor stored in the context.
156+
func As(ctx context.Context, actor rbac.Subject) context.Context {
157+
return context.WithValue(ctx, authContextKey{}, actor)
122158
}
123159

124160
//

coderd/httpmw/apikey.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ func ExtractAPIKey(cfg ExtractAPIKeyConfig) func(http.Handler) http.Handler {
116116
return func(next http.Handler) http.Handler {
117117
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
118118
ctx := r.Context()
119-
systemCtx := dbauthz.WithAuthorizeSystemContext(ctx, rbac.RolesAdminSystem())
119+
// systemCtx := dbauthz.WithAuthorizeSystemContext(ctx, rbac.RolesAdminSystem())
120120
// Write wraps writing a response to redirect if the handler
121121
// specified it should. This redirect is used for user-facing pages
122122
// like workspace applications.
@@ -161,7 +161,7 @@ func ExtractAPIKey(cfg ExtractAPIKeyConfig) func(http.Handler) http.Handler {
161161
return
162162
}
163163

164-
key, err := cfg.DB.GetAPIKeyByID(systemCtx, keyID)
164+
key, err := cfg.DB.GetAPIKeyByID(dbauthz.AsSystem(ctx), keyID)
165165
if err != nil {
166166
if errors.Is(err, sql.ErrNoRows) {
167167
optionalWrite(http.StatusUnauthorized, codersdk.Response{
@@ -194,7 +194,7 @@ func ExtractAPIKey(cfg ExtractAPIKeyConfig) func(http.Handler) http.Handler {
194194
changed = false
195195
)
196196
if key.LoginType == database.LoginTypeGithub || key.LoginType == database.LoginTypeOIDC {
197-
link, err = cfg.DB.GetUserLinkByUserIDLoginType(systemCtx, database.GetUserLinkByUserIDLoginTypeParams{
197+
link, err = cfg.DB.GetUserLinkByUserIDLoginType(dbauthz.AsSystem(ctx), database.GetUserLinkByUserIDLoginTypeParams{
198198
UserID: key.UserID,
199199
LoginType: key.LoginType,
200200
})
@@ -277,7 +277,7 @@ func ExtractAPIKey(cfg ExtractAPIKeyConfig) func(http.Handler) http.Handler {
277277
}
278278
}
279279
if changed {
280-
err := cfg.DB.UpdateAPIKeyByID(systemCtx, database.UpdateAPIKeyByIDParams{
280+
err := cfg.DB.UpdateAPIKeyByID(dbauthz.AsSystem(ctx), database.UpdateAPIKeyByIDParams{
281281
ID: key.ID,
282282
LastUsed: key.LastUsed,
283283
ExpiresAt: key.ExpiresAt,
@@ -293,7 +293,7 @@ func ExtractAPIKey(cfg ExtractAPIKeyConfig) func(http.Handler) http.Handler {
293293
// If the API Key is associated with a user_link (e.g. Github/OIDC)
294294
// then we want to update the relevant oauth fields.
295295
if link.UserID != uuid.Nil {
296-
link, err = cfg.DB.UpdateUserLink(systemCtx, database.UpdateUserLinkParams{
296+
link, err = cfg.DB.UpdateUserLink(dbauthz.AsSystem(ctx), database.UpdateUserLinkParams{
297297
UserID: link.UserID,
298298
LoginType: link.LoginType,
299299
OAuthAccessToken: link.OAuthAccessToken,
@@ -312,7 +312,7 @@ func ExtractAPIKey(cfg ExtractAPIKeyConfig) func(http.Handler) http.Handler {
312312
// We only want to update this occasionally to reduce DB write
313313
// load. We update alongside the UserLink and APIKey since it's
314314
// easier on the DB to colocate writes.
315-
_, err = cfg.DB.UpdateUserLastSeenAt(systemCtx, database.UpdateUserLastSeenAtParams{
315+
_, err = cfg.DB.UpdateUserLastSeenAt(dbauthz.AsSystem(ctx), database.UpdateUserLastSeenAtParams{
316316
ID: key.UserID,
317317
LastSeenAt: database.Now(),
318318
UpdatedAt: database.Now(),
@@ -329,7 +329,7 @@ func ExtractAPIKey(cfg ExtractAPIKeyConfig) func(http.Handler) http.Handler {
329329
// If the key is valid, we also fetch the user roles and status.
330330
// The roles are used for RBAC authorize checks, and the status
331331
// is to block 'suspended' users from accessing the platform.
332-
roles, err := cfg.DB.GetAuthorizationUserRoles(systemCtx, key.UserID)
332+
roles, err := cfg.DB.GetAuthorizationUserRoles(dbauthz.AsSystem(ctx), key.UserID)
333333
if err != nil {
334334
write(http.StatusUnauthorized, codersdk.Response{
335335
Message: internalErrorMessage,
@@ -358,7 +358,7 @@ func ExtractAPIKey(cfg ExtractAPIKeyConfig) func(http.Handler) http.Handler {
358358
Actor: actor,
359359
})
360360
// Set the auth context for the authzquerier as well.
361-
ctx = dbauthz.WithAuthorizeContext(ctx, actor)
361+
ctx = dbauthz.As(ctx, actor)
362362

363363
next.ServeHTTP(rw, r.WithContext(ctx))
364364
})

coderd/httpmw/system_auth_ctx.go

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,10 @@
11
package httpmw
22

3-
import (
4-
"net/http"
5-
6-
"github.com/coder/coder/coderd/database/dbauthz"
7-
"github.com/coder/coder/coderd/rbac"
8-
)
9-
103
// SystemAuthCtx sets the system auth context for the request.
114
// Use sparingly.
12-
func SystemAuthCtx(next http.Handler) http.Handler {
13-
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
14-
ctx := dbauthz.WithAuthorizeSystemContext(r.Context(), rbac.RolesAdminSystem())
15-
next.ServeHTTP(rw, r.WithContext(ctx))
16-
})
17-
}
5+
// func SystemAuthCtx(next http.Handler) http.Handler {
6+
// return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
7+
// ctx := dbauthz.AsSystem(r.Context())
8+
// next.ServeHTTP(rw, r.WithContext(ctx))
9+
// })
10+
// }

coderd/httpmw/userparam.go

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import (
1313
"github.com/coder/coder/coderd/database"
1414
"github.com/coder/coder/coderd/database/dbauthz"
1515
"github.com/coder/coder/coderd/httpapi"
16-
"github.com/coder/coder/coderd/rbac"
1716
"github.com/coder/coder/codersdk"
1817
)
1918

@@ -43,10 +42,9 @@ func ExtractUserParam(db database.Store, redirectToLoginOnMe bool) func(http.Han
4342
return func(next http.Handler) http.Handler {
4443
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
4544
var (
46-
ctx = r.Context()
47-
systemCtx = dbauthz.WithAuthorizeSystemContext(ctx, rbac.RolesAdminSystem())
48-
user database.User
49-
err error
45+
ctx = r.Context()
46+
user database.User
47+
err error
5048
)
5149

5250
// userQuery is either a uuid, a username, or 'me'
@@ -71,7 +69,7 @@ func ExtractUserParam(db database.Store, redirectToLoginOnMe bool) func(http.Han
7169
})
7270
return
7371
}
74-
user, err = db.GetUserByID(systemCtx, apiKey.UserID)
72+
user, err = db.GetUserByID(dbauthz.AsSystem(ctx), apiKey.UserID)
7573
if xerrors.Is(err, sql.ErrNoRows) {
7674
httpapi.ResourceNotFound(rw)
7775
return
@@ -85,7 +83,7 @@ func ExtractUserParam(db database.Store, redirectToLoginOnMe bool) func(http.Han
8583
}
8684
} else if userID, err := uuid.Parse(userQuery); err == nil {
8785
// If the userQuery is a valid uuid
88-
user, err = db.GetUserByID(systemCtx, userID)
86+
user, err = db.GetUserByID(dbauthz.AsSystem(ctx), userID)
8987
if err != nil {
9088
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
9189
Message: userErrorMessage,
@@ -94,7 +92,7 @@ func ExtractUserParam(db database.Store, redirectToLoginOnMe bool) func(http.Han
9492
}
9593
} else {
9694
// Try as a username last
97-
user, err = db.GetUserByEmailOrUsername(systemCtx, database.GetUserByEmailOrUsernameParams{
95+
user, err = db.GetUserByEmailOrUsername(dbauthz.AsSystem(ctx), database.GetUserByEmailOrUsernameParams{
9896
Username: userQuery,
9997
})
10098
if err != nil {

coderd/httpmw/workspaceagent.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func ExtractWorkspaceAgent(db database.Store) func(http.Handler) http.Handler {
3232
return func(next http.Handler) http.Handler {
3333
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
3434
ctx := r.Context()
35-
systemCtx := dbauthz.WithAuthorizeSystemContext(ctx, rbac.RolesAdminSystem())
35+
// dbauthz.AsSystem(ctx) := dbauthz.WithAuthorizeSystemContext(ctx, rbac.RolesAdminSystem())
3636
tokenValue := apiTokenFromRequest(r)
3737
if tokenValue == "" {
3838
httpapi.Write(ctx, rw, http.StatusUnauthorized, codersdk.Response{
@@ -48,7 +48,7 @@ func ExtractWorkspaceAgent(db database.Store) func(http.Handler) http.Handler {
4848
})
4949
return
5050
}
51-
agent, err := db.GetWorkspaceAgentByAuthToken(systemCtx, token)
51+
agent, err := db.GetWorkspaceAgentByAuthToken(dbauthz.AsSystem(ctx), token)
5252
if err != nil {
5353
if errors.Is(err, sql.ErrNoRows) {
5454
httpapi.Write(ctx, rw, http.StatusUnauthorized, codersdk.Response{
@@ -65,7 +65,7 @@ func ExtractWorkspaceAgent(db database.Store) func(http.Handler) http.Handler {
6565
return
6666
}
6767

68-
subject, err := getAgentSubject(systemCtx, db, agent)
68+
subject, err := getAgentSubject(dbauthz.AsSystem(ctx), db, agent)
6969
if err != nil {
7070
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
7171
Message: "Internal error fetching workspace agent.",
@@ -75,7 +75,8 @@ func ExtractWorkspaceAgent(db database.Store) func(http.Handler) http.Handler {
7575
}
7676

7777
ctx = context.WithValue(ctx, workspaceAgentContextKey{}, agent)
78-
ctx = dbauthz.WithAuthorizeContext(ctx, subject)
78+
// Also set the dbauthz actor for the request.
79+
ctx = dbauthz.As(ctx, subject)
7980
next.ServeHTTP(rw, r.WithContext(ctx))
8081
})
8182
}

coderd/metricscache/metricscache.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import (
1515
"cdr.dev/slog"
1616
"github.com/coder/coder/coderd/database"
1717
"github.com/coder/coder/coderd/database/dbauthz"
18-
"github.com/coder/coder/coderd/rbac"
1918
"github.com/coder/coder/codersdk"
2019
"github.com/coder/retry"
2120
)
@@ -144,8 +143,8 @@ func countUniqueUsers(rows []database.GetTemplateDAUsRow) int {
144143
}
145144

146145
func (c *Cache) refresh(ctx context.Context) error {
147-
systemCtx := dbauthz.WithAuthorizeSystemContext(ctx, rbac.RolesAdminSystem())
148-
err := c.database.DeleteOldAgentStats(systemCtx)
146+
// dbauthz.AsSystem(ctx) := dbauthz.WithAuthorizeSystemContext(ctx, rbac.RolesAdminSystem())
147+
err := c.database.DeleteOldAgentStats(dbauthz.AsSystem(ctx))
149148
if err != nil {
150149
return xerrors.Errorf("delete old stats: %w", err)
151150
}
@@ -162,22 +161,22 @@ func (c *Cache) refresh(ctx context.Context) error {
162161
templateAverageBuildTimes = make(map[uuid.UUID]database.GetTemplateAverageBuildTimeRow)
163162
)
164163

165-
rows, err := c.database.GetDeploymentDAUs(systemCtx)
164+
rows, err := c.database.GetDeploymentDAUs(dbauthz.AsSystem(ctx))
166165
if err != nil {
167166
return err
168167
}
169168
deploymentDAUs = convertDeploymentDAUResponse(rows)
170169
c.deploymentDAUResponses.Store(&deploymentDAUs)
171170

172171
for _, template := range templates {
173-
rows, err := c.database.GetTemplateDAUs(systemCtx, template.ID)
172+
rows, err := c.database.GetTemplateDAUs(dbauthz.AsSystem(ctx), template.ID)
174173
if err != nil {
175174
return err
176175
}
177176
templateDAUs[template.ID] = convertDAUResponse(rows)
178177
templateUniqueUsers[template.ID] = countUniqueUsers(rows)
179178

180-
templateAvgBuildTime, err := c.database.GetTemplateAverageBuildTime(systemCtx, database.GetTemplateAverageBuildTimeParams{
179+
templateAvgBuildTime, err := c.database.GetTemplateAverageBuildTime(dbauthz.AsSystem(ctx), database.GetTemplateAverageBuildTimeParams{
181180
TemplateID: uuid.NullUUID{
182181
UUID: template.ID,
183182
Valid: true,

0 commit comments

Comments
 (0)