Skip to content

Commit 26d3497

Browse files
committed
chore: Allow regular users to query for all workspaces
1 parent a983416 commit 26d3497

File tree

8 files changed

+86
-21
lines changed

8 files changed

+86
-21
lines changed

coderd/authorize.go

+24-18
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ type HTTPAuthorizer struct {
5151
// return
5252
// }
5353
func (api *API) Authorize(r *http.Request, action rbac.Action, object rbac.Objecter) bool {
54-
return api.HTTPAuth.Authorize(r, action, object)
54+
return api.HTTPAuth.Authorize(r, action, object, true)
5555
}
5656

5757
// Authorize will return false if the user is not authorized to do the action.
@@ -63,27 +63,33 @@ func (api *API) Authorize(r *http.Request, action rbac.Action, object rbac.Objec
6363
// httpapi.Forbidden(rw)
6464
// return
6565
// }
66-
func (h *HTTPAuthorizer) Authorize(r *http.Request, action rbac.Action, object rbac.Objecter) bool {
66+
func (h *HTTPAuthorizer) Authorize(r *http.Request, action rbac.Action, object rbac.Objecter, logUnauthorized bool) bool {
6767
roles := httpmw.UserAuthorization(r)
6868
err := h.Authorizer.Authorize(r.Context(), roles.Actor, action, object.RBACObject())
6969
if err != nil {
70-
// Log the errors for debugging
71-
internalError := new(rbac.UnauthorizedError)
72-
logger := h.Logger
73-
if xerrors.As(err, internalError) {
74-
logger = h.Logger.With(slog.F("internal", internalError.Internal()))
70+
// Sometimes we do not want to log the unauthorized errors.
71+
// Example: If an endpoint expects the normal case to return unauthorized
72+
// to check a user is not an admin, we do not want to log that since it is
73+
// the expected path.
74+
if logUnauthorized {
75+
// Log the errors for debugging
76+
internalError := new(rbac.UnauthorizedError)
77+
logger := h.Logger
78+
if xerrors.As(err, internalError) {
79+
logger = h.Logger.With(slog.F("internal", internalError.Internal()))
80+
}
81+
// Log information for debugging. This will be very helpful
82+
// in the early days
83+
logger.Warn(r.Context(), "unauthorized",
84+
slog.F("roles", roles.Actor.SafeRoleNames()),
85+
slog.F("actor_id", roles.Actor.ID),
86+
slog.F("actor_name", roles.ActorName),
87+
slog.F("scope", roles.Actor.SafeScopeName()),
88+
slog.F("route", r.URL.Path),
89+
slog.F("action", action),
90+
slog.F("object", object),
91+
)
7592
}
76-
// Log information for debugging. This will be very helpful
77-
// in the early days
78-
logger.Warn(r.Context(), "unauthorized",
79-
slog.F("roles", roles.Actor.SafeRoleNames()),
80-
slog.F("actor_id", roles.Actor.ID),
81-
slog.F("actor_name", roles.ActorName),
82-
slog.F("scope", roles.Actor.SafeScopeName()),
83-
slog.F("route", r.URL.Path),
84-
slog.F("action", action),
85-
slog.F("object", object),
86-
)
8793

8894
return false
8995
}

coderd/rbac/object.go

+7
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,13 @@ var (
3636
Type: "workspace_proxy",
3737
}
3838

39+
// ResourceWorkspaceProxyMetaData is a special resource that is used to
40+
// allow reading metadata for a given workspace proxy. This metadata should
41+
// not be revealed to all users, only administrators of the workspace proxy.
42+
ResourceWorkspaceProxyMetaData = Object{
43+
Type: "workspace_proxy_data",
44+
}
45+
3946
// ResourceWorkspaceExecution CRUD. Org + User owner
4047
// create = workspace remote execution
4148
// read = ?

coderd/rbac/roles.go

+1
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ func ReloadBuiltinRoles(opts *RoleOptions) {
151151
ResourceRoleAssignment.Type: {ActionRead},
152152
// All users can see the provisioner daemons.
153153
ResourceProvisionerDaemon.Type: {ActionRead},
154+
ResourceWorkspaceProxy.Type: {ActionRead},
154155
}),
155156
Org: map[string][]Permission{},
156157
User: allPermsExcept(),

codersdk/workspaceproxy.go

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ const (
3131
type WorkspaceProxyStatus struct {
3232
Status ProxyHealthStatus `json:"status" table:"status"`
3333
// Report provides more information about the health of the workspace proxy.
34+
// This is not provided if the user does not have permission to view workspace
35+
// proxy metadata.
3436
Report ProxyHealthReport `json:"report,omitempty" table:"report"`
3537
CheckedAt time.Time `json:"checked_at" table:"checked_at" format:"date-time"`
3638
}

enterprise/coderd/coderd.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ func New(ctx context.Context, options *Options) (*API, error) {
9393
r.Use(apiKeyMiddleware)
9494
r.Post("/", api.reconnectingPTYSignedToken)
9595
})
96+
// These routes are for administering and managing workspace proxies.
9697
r.Route("/workspaceproxies", func(r chi.Router) {
9798
r.Use(
9899
api.moonsEnabledMW,
@@ -512,5 +513,5 @@ func (api *API) runEntitlementsLoop(ctx context.Context) {
512513
}
513514

514515
func (api *API) Authorize(r *http.Request, action rbac.Action, object rbac.Objecter) bool {
515-
return api.AGPL.HTTPAuth.Authorize(r, action, object)
516+
return api.AGPL.HTTPAuth.Authorize(r, action, object, true)
516517
}

enterprise/coderd/workspaceproxy.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ func (api *API) postWorkspaceProxy(rw http.ResponseWriter, r *http.Request) {
187187

188188
aReq.New = proxy
189189
httpapi.Write(ctx, rw, http.StatusCreated, codersdk.CreateWorkspaceProxyResponse{
190-
Proxy: convertProxy(proxy, proxyhealth.ProxyStatus{
190+
Proxy: api.convertProxy(r, proxy, proxyhealth.ProxyStatus{
191191
Proxy: proxy,
192192
CheckedAt: time.Now(),
193193
Status: proxyhealth.Unregistered,

enterprise/coderd/workspaceproxy_test.go

+48
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import (
1717
"cdr.dev/slog/sloggers/slogtest"
1818
"github.com/coder/coder/agent"
1919
"github.com/coder/coder/coderd/coderdtest"
20+
"github.com/coder/coder/coderd/database"
21+
"github.com/coder/coder/coderd/database/dbauthz"
2022
"github.com/coder/coder/coderd/database/dbtestutil"
2123
"github.com/coder/coder/coderd/workspaceapps"
2224
"github.com/coder/coder/codersdk"
@@ -245,6 +247,52 @@ func TestWorkspaceProxyCRUD(t *testing.T) {
245247
})
246248
}
247249

250+
// TestWorkspaceProxyRead ensures regular uses cannot get report information.
251+
func TestWorkspaceProxyRead(t *testing.T) {
252+
t.Parallel()
253+
254+
dv := coderdtest.DeploymentValues(t)
255+
dv.Experiments = []string{
256+
string(codersdk.ExperimentMoons),
257+
"*",
258+
}
259+
client, _, api := coderdenttest.NewWithAPI(t, &coderdenttest.Options{
260+
Options: &coderdtest.Options{
261+
DeploymentValues: dv,
262+
},
263+
})
264+
first := coderdtest.CreateFirstUser(t, client)
265+
member, _ := coderdtest.CreateAnotherUser(t, client, first.OrganizationID)
266+
_ = coderdenttest.AddLicense(t, client, coderdenttest.LicenseOptions{
267+
Features: license.Features{
268+
codersdk.FeatureWorkspaceProxy: 1,
269+
},
270+
})
271+
272+
ctx := testutil.Context(t, testutil.WaitLong)
273+
proxyRes, err := client.CreateWorkspaceProxy(ctx, codersdk.CreateWorkspaceProxyRequest{
274+
Name: namesgenerator.GetRandomName(1),
275+
Icon: "/emojis/flag.png",
276+
})
277+
require.NoError(t, err)
278+
279+
//nolint:gocritic // System func
280+
_, err = api.Database.RegisterWorkspaceProxy(dbauthz.AsSystemRestricted(ctx), database.RegisterWorkspaceProxyParams{
281+
ID: proxyRes.Proxy.ID,
282+
Url: "http://bad-never-resolves.random",
283+
})
284+
require.NoError(t, err, "failed to register workspace proxy")
285+
286+
proxies, err := client.WorkspaceProxies(ctx)
287+
require.NoError(t, err, "failed to get workspace proxies")
288+
fmt.Println(proxies)
289+
290+
proxies, err = member.WorkspaceProxies(ctx)
291+
require.NoError(t, err, "failed to get workspace proxies")
292+
fmt.Println(proxies)
293+
294+
}
295+
248296
func TestIssueSignedAppToken(t *testing.T) {
249297
t.Parallel()
250298

scripts/develop.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ fatal() {
185185
# Create the proxy
186186
proxy_session_token=$("${CODER_DEV_SHIM}" proxy create --name=local-proxy --display-name="Local Proxy" --icon="/emojis/1f4bb.png" --only-token)
187187
# Start the proxy
188-
start_cmd PROXY "" "${CODER_DEV_SHIM}" proxy server --http-address=localhost:3010 --proxy-session-token="${proxy_session_token}" --primary-access-url=http://localhost:3000
188+
start_cmd PROXY "" "${CODER_DEV_SHIM}" proxy server --access-url=http://127.0.0.1:3010 --http-address=127.0.0.1:3010 --proxy-session-token="${proxy_session_token}" --primary-access-url=http://localhost:3000
189189
) || echo "Failed to create workspace proxy. No workspace proxy created."
190190
fi
191191

0 commit comments

Comments
 (0)