fleet/server/service/middleware/authzcheck/authzcheck.go
Victor Lyuboslavsky 722a206115
Fix 500 return code for several endpoints. (#14859)
Fixed 500 return code from several endpoints.

/api/v1/fleet/perform_required_password_reset
- Now returns 403 when Authorization token is missing

/api/v1/fleet/hosts_summary
- Now returns 400 when low_disk_space parameter is invalid

/api/v1/fleet/demologin
- Now returns 403

/api/v1/fleet/sessions/*
- Now returns 400 on invalid input

#12274

# Checklist for submitter

If some of the following don't apply, delete the relevant line.

- [x] Changes file added for user-visible changes in `changes/` or
`orbit/changes/`.
See [Changes
files](https://fleetdm.com/docs/contributing/committing-changes#changes-files)
for more information.
- [x] Added/updated tests
- [x] Manual QA for all new/changed functionality
2023-11-02 12:32:34 -05:00

61 lines
2.2 KiB
Go

// Package authzcheck implements a middleware that ensures that an authorization
// check was performed. This does not ensure that the correct authorization
// check was performed, but offers a backstop in case that a developer misses a
// check.
package authzcheck
import (
"context"
"errors"
"github.com/fleetdm/fleet/v4/server/authz"
authz_ctx "github.com/fleetdm/fleet/v4/server/contexts/authz"
"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/go-kit/kit/endpoint"
)
// Middleware is the authzcheck middleware type.
type Middleware struct{}
// NewMiddleware returns a new authzcheck middleware.
func NewMiddleware() *Middleware {
return &Middleware{}
}
func (m *Middleware) AuthzCheck() endpoint.Middleware {
return func(next endpoint.Endpoint) endpoint.Endpoint {
return func(ctx context.Context, req interface{}) (interface{}, error) {
authzctx := &authz_ctx.AuthorizationContext{}
ctx = authz_ctx.NewContext(ctx, authzctx)
response, err := next(ctx, req)
// If authentication check failed, return that error (so that we log
// appropriately).
var authFailedError *fleet.AuthFailedError
var authRequiredError *fleet.AuthRequiredError
var authHeaderRequiredError *fleet.AuthHeaderRequiredError
if errors.As(err, &authFailedError) ||
errors.As(err, &authRequiredError) ||
errors.As(err, &authHeaderRequiredError) ||
errors.Is(err, fleet.ErrPasswordResetRequired) {
return nil, err
}
// TODO(mna): currently, any error detected before an authorization check gets
// lost and the response is always Unauthorized because of the following condition.
// I _think_ it would be safe to check here of response.error() returns a non-nil
// error and if so, leave that error go through instead of returning a check missing
// authorization error. To look into when addressing #4406.
// If authorization was not checked, return a response that will
// marshal to a generic error and log that the check was missed.
if !authzctx.Checked() {
// Getting to here means there is an authorization-related bug in our code.
return nil, authz.CheckMissingWithResponse(response)
}
return response, err
}
}
}