Skip to content

Commit 4ecfd7f

Browse files
committed
allow workspace update permissions to access agents
1 parent 4b82509 commit 4ecfd7f

File tree

5 files changed

+32
-21
lines changed

5 files changed

+32
-21
lines changed

coderd/coderd.go

+1
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ func New(options *Options) *API {
291291
r.Use(
292292
apiKeyMiddleware,
293293
httpmw.ExtractWorkspaceAgentParam(options.Database),
294+
httpmw.ExtractWorkspaceParam(options.Database),
294295
)
295296
r.Get("/", api.workspaceAgent)
296297
r.Get("/dial", api.workspaceAgentDial)

coderd/coderd_test.go

+13-3
Original file line numberDiff line numberDiff line change
@@ -153,10 +153,7 @@ func TestAuthorizeAllEndpoints(t *testing.T) {
153153
"GET:/api/v2/workspaceagents/me/listen": {NoAuthorize: true},
154154
"GET:/api/v2/workspaceagents/me/metadata": {NoAuthorize: true},
155155
"GET:/api/v2/workspaceagents/me/turn": {NoAuthorize: true},
156-
"GET:/api/v2/workspaceagents/{workspaceagent}": {NoAuthorize: true},
157-
"GET:/api/v2/workspaceagents/{workspaceagent}/dial": {NoAuthorize: true},
158156
"GET:/api/v2/workspaceagents/{workspaceagent}/iceservers": {NoAuthorize: true},
159-
"GET:/api/v2/workspaceagents/{workspaceagent}/pty": {NoAuthorize: true},
160157
"GET:/api/v2/workspaceagents/{workspaceagent}/turn": {NoAuthorize: true},
161158

162159
// These endpoints have more assertions. This is good, add more endpoints to assert if you can!
@@ -210,6 +207,18 @@ func TestAuthorizeAllEndpoints(t *testing.T) {
210207
AssertAction: rbac.ActionRead,
211208
AssertObject: workspaceRBACObj,
212209
},
210+
"GET:/api/v2/workspaceagents/{workspaceagent}": {
211+
AssertAction: rbac.ActionRead,
212+
AssertObject: workspaceRBACObj,
213+
},
214+
"GET:/api/v2/workspaceagents/{workspaceagent}/dial": {
215+
AssertAction: rbac.ActionUpdate,
216+
AssertObject: workspaceRBACObj,
217+
},
218+
"GET:/api/v2/workspaceagents/{workspaceagent}/pty": {
219+
AssertAction: rbac.ActionUpdate,
220+
AssertObject: workspaceRBACObj,
221+
},
213222
"GET:/api/v2/workspaces/": {
214223
StatusCode: http.StatusOK,
215224
AssertAction: rbac.ActionRead,
@@ -378,6 +387,7 @@ func TestAuthorizeAllEndpoints(t *testing.T) {
378387
route = strings.ReplaceAll(route, "{workspacebuild}", workspace.LatestBuild.ID.String())
379388
route = strings.ReplaceAll(route, "{workspacename}", workspace.Name)
380389
route = strings.ReplaceAll(route, "{workspacebuildname}", workspace.LatestBuild.Name)
390+
route = strings.ReplaceAll(route, "{workspaceagent}", workspaceResources[0].Agents[0].ID.String())
381391
route = strings.ReplaceAll(route, "{template}", template.ID.String())
382392
route = strings.ReplaceAll(route, "{hash}", file.Hash)
383393
route = strings.ReplaceAll(route, "{workspaceresource}", workspaceResources[0].ID.String())

coderd/httpmw/apikey.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@ type userRolesKey struct{}
3737
// AuthorizationUserRoles returns the roles used for authorization.
3838
// Comes from the ExtractAPIKey handler.
3939
func AuthorizationUserRoles(r *http.Request) database.GetAuthorizationUserRolesRow {
40-
apiKey, ok := r.Context().Value(userRolesKey{}).(database.GetAuthorizationUserRolesRow)
40+
userRoles, ok := r.Context().Value(userRolesKey{}).(database.GetAuthorizationUserRolesRow)
4141
if !ok {
4242
panic("developer error: user roles middleware not provided")
4343
}
44-
return apiKey
44+
return userRoles
4545
}
4646

4747
// OAuth2Configs is a collection of configurations for OAuth-based authentication.

coderd/httpmw/workspaceagentparam.go

+3-16
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66
"errors"
77
"net/http"
88

9+
"github.com/go-chi/chi/v5"
10+
911
"github.com/coder/coder/coderd/database"
1012
"github.com/coder/coder/coderd/httpapi"
1113
)
@@ -74,24 +76,9 @@ func ExtractWorkspaceAgentParam(db database.Store) func(http.Handler) http.Handl
7476
})
7577
return
7678
}
77-
workspace, err := db.GetWorkspaceByID(r.Context(), build.WorkspaceID)
78-
if err != nil {
79-
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
80-
Message: "Internal error fetching workspace.",
81-
Detail: err.Error(),
82-
})
83-
return
84-
}
85-
86-
apiKey := APIKey(r)
87-
if apiKey.UserID != workspace.OwnerID {
88-
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
89-
Message: "Getting non-personal agents isn't supported.",
90-
})
91-
return
92-
}
9379

9480
ctx := context.WithValue(r.Context(), workspaceAgentParamContextKey{}, agent)
81+
chi.RouteContext(ctx).URLParams.Add("workspace", build.WorkspaceID.String())
9582
next.ServeHTTP(rw, r.WithContext(ctx))
9683
})
9784
}

coderd/workspaceagents.go

+13
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/coder/coder/coderd/database"
2222
"github.com/coder/coder/coderd/httpapi"
2323
"github.com/coder/coder/coderd/httpmw"
24+
"github.com/coder/coder/coderd/rbac"
2425
"github.com/coder/coder/coderd/turnconn"
2526
"github.com/coder/coder/codersdk"
2627
"github.com/coder/coder/peer"
@@ -31,6 +32,10 @@ import (
3132

3233
func (api *API) workspaceAgent(rw http.ResponseWriter, r *http.Request) {
3334
workspaceAgent := httpmw.WorkspaceAgentParam(r)
35+
workspace := httpmw.WorkspaceParam(r)
36+
if !api.Authorize(rw, r, rbac.ActionRead, workspace) {
37+
return
38+
}
3439
dbApps, err := api.Database.GetWorkspaceAppsByAgentID(r.Context(), workspaceAgent.ID)
3540
if err != nil && !xerrors.Is(err, sql.ErrNoRows) {
3641
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
@@ -58,6 +63,10 @@ func (api *API) workspaceAgentDial(rw http.ResponseWriter, r *http.Request) {
5863
defer api.websocketWaitGroup.Done()
5964

6065
workspaceAgent := httpmw.WorkspaceAgentParam(r)
66+
workspace := httpmw.WorkspaceParam(r)
67+
if !api.Authorize(rw, r, rbac.ActionUpdate, workspace) {
68+
return
69+
}
6170
apiAgent, err := convertWorkspaceAgent(workspaceAgent, nil, api.AgentConnectionUpdateFrequency)
6271
if err != nil {
6372
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
@@ -369,6 +378,10 @@ func (api *API) workspaceAgentPTY(rw http.ResponseWriter, r *http.Request) {
369378
defer api.websocketWaitGroup.Done()
370379

371380
workspaceAgent := httpmw.WorkspaceAgentParam(r)
381+
workspace := httpmw.WorkspaceParam(r)
382+
if !api.Authorize(rw, r, rbac.ActionUpdate, workspace) {
383+
return
384+
}
372385
apiAgent, err := convertWorkspaceAgent(workspaceAgent, nil, api.AgentConnectionUpdateFrequency)
373386
if err != nil {
374387
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{

0 commit comments

Comments
 (0)