Skip to content

feat: Return more 404s vs 403s #2194

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

Merged
merged 16 commits into from
Jun 14, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Return vague 404
  • Loading branch information
Emyrk committed Jun 10, 2022
commit 815baf96b4757dbc5221fac4a5a554513e4b2ad1
4 changes: 2 additions & 2 deletions coderd/files.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func (api *API) fileByHash(rw http.ResponseWriter, r *http.Request) {
}
file, err := api.Database.GetFileByHash(r.Context(), hash)
if errors.Is(err, sql.ErrNoRows) {
httpapi.ResourceNotFound(rw, fmt.Sprintf("File %q", hash))
httpapi.ResourceNotFound(rw)
return
}
if err != nil {
Expand All @@ -101,7 +101,7 @@ func (api *API) fileByHash(rw http.ResponseWriter, r *http.Request) {
if !api.Authorize(r, rbac.ActionRead,
rbac.ResourceFile.WithOwner(file.CreatedBy.String()).WithID(file.Hash)) {
// Return 404 to not leak the file exists
httpapi.ResourceNotFound(rw, fmt.Sprintf("File %q", hash))
httpapi.ResourceNotFound(rw)
return
}

Expand Down
4 changes: 2 additions & 2 deletions coderd/gitsshkey.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func (api *API) regenerateGitSSHKey(rw http.ResponseWriter, r *http.Request) {
user := httpmw.UserParam(r)

if !api.Authorize(r, rbac.ActionUpdate, rbac.ResourceUserData.WithOwner(user.ID.String())) {
httpapi.Forbidden(rw)
httpapi.ResourceNotFound(rw)
return
}

Expand Down Expand Up @@ -64,7 +64,7 @@ func (api *API) gitSSHKey(rw http.ResponseWriter, r *http.Request) {
user := httpmw.UserParam(r)

if !api.Authorize(r, rbac.ActionRead, rbac.ResourceUserData.WithOwner(user.ID.String())) {
httpapi.Forbidden(rw)
httpapi.ResourceNotFound(rw)
return
}

Expand Down
6 changes: 4 additions & 2 deletions coderd/httpapi/httpapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,11 @@ type Error struct {
Detail string `json:"detail" validate:"required"`
}

func ResourceNotFound(rw http.ResponseWriter, resource string) {
// ResourceNotFound is intentionally vague. All 404 responses should be identical
// to prevent leaking existence of resources.
func ResourceNotFound(rw http.ResponseWriter) {
Write(rw, http.StatusNotFound, Response{
Message: fmt.Sprintf("%s does not exist.", resource),
Message: fmt.Sprintf("Resource not found"),
})
}

Expand Down
3 changes: 1 addition & 2 deletions coderd/httpmw/organizationparam.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"database/sql"
"errors"
"fmt"
"net/http"

"github.com/coder/coder/coderd/database"
Expand Down Expand Up @@ -45,7 +44,7 @@ func ExtractOrganizationParam(db database.Store) func(http.Handler) http.Handler

organization, err := db.GetOrganizationByID(r.Context(), orgID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.ResourceNotFound(rw, fmt.Sprintf("Organization %q", orgID))
httpapi.ResourceNotFound(rw)
return
}
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion coderd/httpmw/templateparam.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func ExtractTemplateParam(db database.Store) func(http.Handler) http.Handler {
}

if template.Deleted {
httpapi.ResourceNotFound(rw, fmt.Sprintf("Template %q", templateID))
httpapi.ResourceNotFound(rw)
return
}

Expand Down
3 changes: 1 addition & 2 deletions coderd/httpmw/templateversionparam.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"database/sql"
"errors"
"fmt"
"net/http"

"github.com/go-chi/chi/v5"
Expand Down Expand Up @@ -34,7 +33,7 @@ func ExtractTemplateVersionParam(db database.Store) func(http.Handler) http.Hand
}
templateVersion, err := db.GetTemplateVersionByID(r.Context(), templateVersionID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.ResourceNotFound(rw, fmt.Sprintf("Template version %q", templateVersionID))
httpapi.ResourceNotFound(rw)
return
}
if err != nil {
Expand Down
7 changes: 7 additions & 0 deletions coderd/httpmw/userparam.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ package httpmw

import (
"context"
"database/sql"
"net/http"

"golang.org/x/xerrors"

"github.com/go-chi/chi/v5"
"github.com/google/uuid"

Expand Down Expand Up @@ -47,6 +50,10 @@ func ExtractUserParam(db database.Store) func(http.Handler) http.Handler {

if userQuery == "me" {
user, err = db.GetUserByID(r.Context(), APIKey(r).UserID)
if xerrors.Is(err, sql.ErrNoRows) {
httpapi.ResourceNotFound(rw)
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching user.",
Expand Down
3 changes: 1 addition & 2 deletions coderd/httpmw/workspacebuildparam.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"database/sql"
"errors"
"fmt"
"net/http"

"github.com/go-chi/chi/v5"
Expand Down Expand Up @@ -34,7 +33,7 @@ func ExtractWorkspaceBuildParam(db database.Store) func(http.Handler) http.Handl
}
workspaceBuild, err := db.GetWorkspaceBuildByID(r.Context(), workspaceBuildID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.ResourceNotFound(rw, fmt.Sprintf("Workspace build %q", workspaceBuildID))
httpapi.ResourceNotFound(rw)
return
}
if err != nil {
Expand Down
3 changes: 1 addition & 2 deletions coderd/httpmw/workspaceparam.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"database/sql"
"errors"
"fmt"
"net/http"

"github.com/coder/coder/coderd/database"
Expand Down Expand Up @@ -32,7 +31,7 @@ func ExtractWorkspaceParam(db database.Store) func(http.Handler) http.Handler {
}
workspace, err := db.GetWorkspaceByID(r.Context(), workspaceID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.ResourceNotFound(rw, fmt.Sprintf("Workspace %q", workspaceID))
httpapi.ResourceNotFound(rw)
return
}
if err != nil {
Expand Down
5 changes: 2 additions & 3 deletions coderd/organizations.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func (api *API) organization(rw http.ResponseWriter, r *http.Request) {
if !api.Authorize(r, rbac.ActionRead, rbac.ResourceOrganization.
InOrg(organization.ID).
WithID(organization.ID.String())) {
httpapi.ResourceNotFound(rw, fmt.Sprintf("Organization %q", organization.ID))
httpapi.ResourceNotFound(rw)
return
}

Expand All @@ -33,8 +33,7 @@ func (api *API) postOrganizations(rw http.ResponseWriter, r *http.Request) {
apiKey := httpmw.APIKey(r)
// Create organization uses the organization resource without an OrgID.
// This means you need the site wide permission to make a new organization.
if !api.Authorize(r, rbac.ActionCreate,
rbac.ResourceOrganization) {
if !api.Authorize(r, rbac.ActionCreate, rbac.ResourceOrganization) {
httpapi.Forbidden(rw)
return
}
Expand Down
8 changes: 4 additions & 4 deletions coderd/parameters.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func (api *API) postParameter(rw http.ResponseWriter, r *http.Request) {
return
}
if !api.Authorize(r, rbac.ActionUpdate, obj) {
httpapi.Forbidden(rw)
httpapi.ResourceNotFound(rw)
return
}

Expand Down Expand Up @@ -87,7 +87,7 @@ func (api *API) parameters(rw http.ResponseWriter, r *http.Request) {
}

if !api.Authorize(r, rbac.ActionRead, obj) {
httpapi.Forbidden(rw)
httpapi.ResourceNotFound(rw)
return
}

Expand Down Expand Up @@ -124,7 +124,7 @@ func (api *API) deleteParameter(rw http.ResponseWriter, r *http.Request) {
}
// A deleted param is still updating the underlying resource for the scope.
if !api.Authorize(r, rbac.ActionUpdate, obj) {
httpapi.ResourceNotFound(rw, fmt.Sprintf("Parameter %q with scope %q", scopeID, scope))
httpapi.ResourceNotFound(rw)
return
}

Expand All @@ -135,7 +135,7 @@ func (api *API) deleteParameter(rw http.ResponseWriter, r *http.Request) {
Name: name,
})
if errors.Is(err, sql.ErrNoRows) {
httpapi.ResourceNotFound(rw, fmt.Sprintf("Parameter %q with scope %q", scopeID, scope))
httpapi.ResourceNotFound(rw)
return
}
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion coderd/roles.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func (api *API) checkPermissions(rw http.ResponseWriter, r *http.Request) {
user := httpmw.UserParam(r)

if !api.Authorize(r, rbac.ActionRead, rbac.ResourceUser.WithID(user.ID.String())) {
httpapi.Forbidden(rw)
httpapi.ResourceNotFound(rw)
return
}

Expand Down
12 changes: 6 additions & 6 deletions coderd/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func (api *API) template(rw http.ResponseWriter, r *http.Request) {
template := httpmw.TemplateParam(r)

if !api.Authorize(r, rbac.ActionRead, template) {
httpapi.ResourceNotFound(rw, fmt.Sprintf("Template %q", template.ID))
httpapi.ResourceNotFound(rw)
return
}

Expand All @@ -56,7 +56,7 @@ func (api *API) template(rw http.ResponseWriter, r *http.Request) {
func (api *API) deleteTemplate(rw http.ResponseWriter, r *http.Request) {
template := httpmw.TemplateParam(r)
if !api.Authorize(r, rbac.ActionDelete, template) {
httpapi.ResourceNotFound(rw, fmt.Sprintf("Template %q", template.ID))
httpapi.ResourceNotFound(rw)
return
}

Expand Down Expand Up @@ -100,7 +100,7 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
var createTemplate codersdk.CreateTemplateRequest
organization := httpmw.OrganizationParam(r)
if !api.Authorize(r, rbac.ActionCreate, rbac.ResourceTemplate.InOrg(organization.ID)) {
httpapi.Forbidden(rw)
httpapi.ResourceNotFound(rw)
return
}

Expand Down Expand Up @@ -273,7 +273,7 @@ func (api *API) templateByOrganizationAndName(rw http.ResponseWriter, r *http.Re
})
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
httpapi.ResourceNotFound(rw, fmt.Sprintf("Template %q in organization %q", templateName, organization.Name))
httpapi.ResourceNotFound(rw)
return
}

Expand All @@ -285,7 +285,7 @@ func (api *API) templateByOrganizationAndName(rw http.ResponseWriter, r *http.Re
}

if !api.Authorize(r, rbac.ActionRead, template) {
httpapi.ResourceNotFound(rw, fmt.Sprintf("Template %q in organization %q", templateName, organization.Name))
httpapi.ResourceNotFound(rw)
return
}

Expand All @@ -312,7 +312,7 @@ func (api *API) templateByOrganizationAndName(rw http.ResponseWriter, r *http.Re
func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
template := httpmw.TemplateParam(r)
if !api.Authorize(r, rbac.ActionUpdate, template) {
httpapi.ResourceNotFound(rw, fmt.Sprintf("Template %q", template.ID))
httpapi.ResourceNotFound(rw)
return
}

Expand Down
30 changes: 15 additions & 15 deletions coderd/templateversions.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
func (api *API) templateVersion(rw http.ResponseWriter, r *http.Request) {
templateVersion := httpmw.TemplateVersionParam(r)
if !api.Authorize(r, rbac.ActionRead, templateVersion) {
httpapi.ResourceNotFound(rw, fmt.Sprintf("Template version %q", templateVersion.ID))
httpapi.ResourceNotFound(rw)
return
}

Expand All @@ -42,7 +42,7 @@ func (api *API) templateVersion(rw http.ResponseWriter, r *http.Request) {
func (api *API) patchCancelTemplateVersion(rw http.ResponseWriter, r *http.Request) {
templateVersion := httpmw.TemplateVersionParam(r)
if !api.Authorize(r, rbac.ActionUpdate, templateVersion) {
httpapi.ResourceNotFound(rw, fmt.Sprintf("Template version %q", templateVersion.ID))
httpapi.ResourceNotFound(rw)
return
}

Expand Down Expand Up @@ -88,7 +88,7 @@ func (api *API) patchCancelTemplateVersion(rw http.ResponseWriter, r *http.Reque
func (api *API) templateVersionSchema(rw http.ResponseWriter, r *http.Request) {
templateVersion := httpmw.TemplateVersionParam(r)
if !api.Authorize(r, rbac.ActionRead, templateVersion) {
httpapi.ResourceNotFound(rw, fmt.Sprintf("Template version %q", templateVersion.ID))
httpapi.ResourceNotFound(rw)
return
}

Expand Down Expand Up @@ -136,7 +136,7 @@ func (api *API) templateVersionParameters(rw http.ResponseWriter, r *http.Reques
apiKey := httpmw.APIKey(r)
templateVersion := httpmw.TemplateVersionParam(r)
if !api.Authorize(r, rbac.ActionRead, templateVersion) {
httpapi.ResourceNotFound(rw, fmt.Sprintf("Template version %q", templateVersion.ID))
httpapi.ResourceNotFound(rw)
return
}

Expand Down Expand Up @@ -180,14 +180,14 @@ func (api *API) postTemplateVersionDryRun(rw http.ResponseWriter, r *http.Reques
apiKey := httpmw.APIKey(r)
templateVersion := httpmw.TemplateVersionParam(r)
if !api.Authorize(r, rbac.ActionRead, templateVersion) {
httpapi.ResourceNotFound(rw, fmt.Sprintf("Template version %q", templateVersion.ID))
httpapi.ResourceNotFound(rw)
return
}
// We use the workspace RBAC check since we don't want to allow dry runs if
// the user can't create workspaces.
if !api.Authorize(r, rbac.ActionCreate,
rbac.ResourceWorkspace.InOrg(templateVersion.OrganizationID).WithOwner(apiKey.UserID.String())) {
httpapi.Forbidden(rw)
httpapi.ResourceNotFound(rw)
return
}

Expand Down Expand Up @@ -301,7 +301,7 @@ func (api *API) patchTemplateVersionDryRunCancel(rw http.ResponseWriter, r *http
}
if !api.Authorize(r, rbac.ActionUpdate,
rbac.ResourceWorkspace.InOrg(templateVersion.OrganizationID).WithOwner(job.InitiatorID.String())) {
httpapi.ResourceNotFound(rw, fmt.Sprintf("Template version %q", templateVersion.ID))
httpapi.ResourceNotFound(rw)
return
}

Expand Down Expand Up @@ -344,7 +344,7 @@ func (api *API) fetchTemplateVersionDryRunJob(rw http.ResponseWriter, r *http.Re
jobID = chi.URLParam(r, "jobID")
)
if !api.Authorize(r, rbac.ActionRead, templateVersion) {
httpapi.ResourceNotFound(rw, fmt.Sprintf("Template version %q", templateVersion.ID))
httpapi.ResourceNotFound(rw)
return database.ProvisionerJob{}, false
}

Expand Down Expand Up @@ -403,7 +403,7 @@ func (api *API) fetchTemplateVersionDryRunJob(rw http.ResponseWriter, r *http.Re
func (api *API) templateVersionsByTemplate(rw http.ResponseWriter, r *http.Request) {
template := httpmw.TemplateParam(r)
if !api.Authorize(r, rbac.ActionRead, template) {
httpapi.ResourceNotFound(rw, fmt.Sprintf("Template %q", template.ID))
httpapi.ResourceNotFound(rw)
return
}

Expand Down Expand Up @@ -491,7 +491,7 @@ func (api *API) templateVersionsByTemplate(rw http.ResponseWriter, r *http.Reque
func (api *API) templateVersionByName(rw http.ResponseWriter, r *http.Request) {
template := httpmw.TemplateParam(r)
if !api.Authorize(r, rbac.ActionRead, template) {
httpapi.ResourceNotFound(rw, fmt.Sprintf("Template %q", template.ID))
httpapi.ResourceNotFound(rw)
return
}

Expand Down Expand Up @@ -531,7 +531,7 @@ func (api *API) templateVersionByName(rw http.ResponseWriter, r *http.Request) {
func (api *API) patchActiveTemplateVersion(rw http.ResponseWriter, r *http.Request) {
template := httpmw.TemplateParam(r)
if !api.Authorize(r, rbac.ActionUpdate, template) {
httpapi.ResourceNotFound(rw, fmt.Sprintf("Template %q", template.ID))
httpapi.ResourceNotFound(rw)
return
}

Expand Down Expand Up @@ -618,12 +618,12 @@ func (api *API) postTemplateVersionsByOrganization(rw http.ResponseWriter, r *ht

// Making a new template version is the same permission as creating a new template.
if !api.Authorize(r, rbac.ActionCreate, rbac.ResourceTemplate.InOrg(organization.ID)) {
httpapi.Forbidden(rw)
httpapi.ResourceNotFound(rw)
return
}

if !api.Authorize(r, rbac.ActionRead, file) {
httpapi.Forbidden(rw)
httpapi.ResourceNotFound(rw)
return
}

Expand Down Expand Up @@ -705,7 +705,7 @@ func (api *API) postTemplateVersionsByOrganization(rw http.ResponseWriter, r *ht
func (api *API) templateVersionResources(rw http.ResponseWriter, r *http.Request) {
templateVersion := httpmw.TemplateVersionParam(r)
if !api.Authorize(r, rbac.ActionRead, templateVersion) {
httpapi.ResourceNotFound(rw, fmt.Sprintf("Template version %q", templateVersion.ID))
httpapi.ResourceNotFound(rw)
return
}

Expand All @@ -727,7 +727,7 @@ func (api *API) templateVersionResources(rw http.ResponseWriter, r *http.Request
func (api *API) templateVersionLogs(rw http.ResponseWriter, r *http.Request) {
templateVersion := httpmw.TemplateVersionParam(r)
if !api.Authorize(r, rbac.ActionRead, templateVersion) {
httpapi.ResourceNotFound(rw, fmt.Sprintf("Template version %q", templateVersion.ID))
httpapi.ResourceNotFound(rw)
return
}

Expand Down
Loading