Files
coder/coderd/authorize.go
Kyle Carberry db0ba8588e chore: Refactor Enterprise code to layer on top of AGPL (#4034)
* chore: Refactor Enterprise code to layer on top of AGPL

This is an experiment to invert the import order of the Enterprise
code to layer on top of AGPL.

* Fix Garrett's comments

* Add pointer.Handle to atomically obtain references

This uses a context to ensure the same value persists through
multiple executions to `Load()`.

* Remove entitlements API from AGPL coderd

* Remove AGPL Coder entitlements endpoint test

* Fix warnings output

* Add command-line flag to toggle audit logging

* Fix hasLicense being set

* Remove features interface

* Fix audit logging default

* Add bash as a dependency

* Add comment

* Add tests for resync and pubsub, and add back previous exp backoff retry

* Separate authz code again

* Add pointer loading example from comment

* Fix duplicate test, remove pointer.Handle

* Fix expired license

* Add entitlements struct

* Fix context passing
2022-09-19 23:11:01 -05:00

84 lines
2.4 KiB
Go

package coderd
import (
"net/http"
"golang.org/x/xerrors"
"cdr.dev/slog"
"github.com/coder/coder/coderd/httpmw"
"github.com/coder/coder/coderd/rbac"
)
func AuthorizeFilter[O rbac.Objecter](h *HTTPAuthorizer, r *http.Request, action rbac.Action, objects []O) ([]O, error) {
roles := httpmw.UserAuthorization(r)
objects, err := rbac.Filter(r.Context(), h.Authorizer, roles.ID.String(), roles.Roles, roles.Scope.ToRBAC(), action, objects)
if err != nil {
// Log the error as Filter should not be erroring.
h.Logger.Error(r.Context(), "filter failed",
slog.Error(err),
slog.F("user_id", roles.ID),
slog.F("username", roles.Username),
slog.F("scope", roles.Scope),
slog.F("route", r.URL.Path),
slog.F("action", action),
)
return nil, err
}
return objects, nil
}
type HTTPAuthorizer struct {
Authorizer rbac.Authorizer
Logger slog.Logger
}
// Authorize will return false if the user is not authorized to do the action.
// This function will log appropriately, but the caller must return an
// error to the api client.
// Eg:
//
// if !api.Authorize(...) {
// httpapi.Forbidden(rw)
// return
// }
func (api *API) Authorize(r *http.Request, action rbac.Action, object rbac.Objecter) bool {
return api.HTTPAuth.Authorize(r, action, object)
}
// Authorize will return false if the user is not authorized to do the action.
// This function will log appropriately, but the caller must return an
// error to the api client.
// Eg:
//
// if !h.Authorize(...) {
// httpapi.Forbidden(rw)
// return
// }
func (h *HTTPAuthorizer) Authorize(r *http.Request, action rbac.Action, object rbac.Objecter) bool {
roles := httpmw.UserAuthorization(r)
err := h.Authorizer.ByRoleName(r.Context(), roles.ID.String(), roles.Roles, roles.Scope.ToRBAC(), action, object.RBACObject())
if err != nil {
// Log the errors for debugging
internalError := new(rbac.UnauthorizedError)
logger := h.Logger
if xerrors.As(err, internalError) {
logger = h.Logger.With(slog.F("internal", internalError.Internal()))
}
// Log information for debugging. This will be very helpful
// in the early days
logger.Warn(r.Context(), "unauthorized",
slog.F("roles", roles.Roles),
slog.F("user_id", roles.ID),
slog.F("username", roles.Username),
slog.F("scope", roles.Scope),
slog.F("route", r.URL.Path),
slog.F("action", action),
slog.F("object", object),
)
return false
}
return true
}