mirror of
https://github.com/hanzoai/o11y.git
synced 2026-10-15 12:58:33 +00:00
32 path-segment reads across users, service accounts, auth domains and roles
stop naming gorilla and read through coretypes.Param. Which router matched the
route is not a fact these handlers should know — the value they need is the
segment.
Each package gains the test it never had: a REAL route template on a real
router, distinct uuids in each segment, and an assertion on which value reached
the store. /users/{id}/roles/{roleId}, /service_accounts/{id}/roles/{rid} and
/service_accounts/{id}/keys/{fid} each carry TWO segments, and a handler that
reads the wrong name still compiles and still answers 2xx — it just acts on the
wrong resource. The self-modification guard in UpdateUser is pinned by body,
because it compares the PATH segment to the caller: read the wrong name and it
compares "" and lets the edit through.
Registration is untouched — {id} literals, *mux.Router and the gates stay put
for the one atomic commit that converts them.
Co-authored-by: Hanzo Dev <[email protected]>
187 lines
4.5 KiB
Go
187 lines
4.5 KiB
Go
package o11yauthzapi
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/hanzoai/o11y/pkg/authz"
|
|
"github.com/hanzoai/o11y/pkg/errors"
|
|
"github.com/hanzoai/o11y/pkg/http/binding"
|
|
"github.com/hanzoai/o11y/pkg/http/render"
|
|
"github.com/hanzoai/o11y/pkg/types"
|
|
"github.com/hanzoai/o11y/pkg/types/authtypes"
|
|
"github.com/hanzoai/o11y/pkg/types/coretypes"
|
|
"github.com/hanzoai/o11y/pkg/valuer"
|
|
)
|
|
|
|
type handler struct {
|
|
authz authz.AuthZ
|
|
}
|
|
|
|
func NewHandler(authz authz.AuthZ) authz.Handler {
|
|
return &handler{authz: authz}
|
|
}
|
|
|
|
func (handler *handler) Create(rw http.ResponseWriter, r *http.Request) {
|
|
ctx := r.Context()
|
|
claims, err := authtypes.ClaimsFromContext(ctx)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
req := new(authtypes.PostableRole)
|
|
if err := binding.JSON.BindBody(r.Body, req); err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
roleWithTransactionGroups := authtypes.NewRoleWithTransactionGroups(req.Name, req.Description, authtypes.RoleTypeCustom, valuer.MustNewUUID(claims.OrgID), req.TransactionGroups)
|
|
err = handler.authz.Create(ctx, valuer.MustNewUUID(claims.OrgID), roleWithTransactionGroups)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
render.Success(rw, http.StatusCreated, types.Identifiable{ID: roleWithTransactionGroups.ID})
|
|
}
|
|
|
|
func (handler *handler) Get(rw http.ResponseWriter, r *http.Request) {
|
|
ctx := r.Context()
|
|
claims, err := authtypes.ClaimsFromContext(ctx)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
id := coretypes.Param(r, "id")
|
|
if id == "" {
|
|
render.Error(rw, errors.New(errors.TypeInvalidInput, authtypes.ErrCodeRoleInvalidInput, "id is missing from the request"))
|
|
return
|
|
}
|
|
roleID, err := valuer.NewUUID(id)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
roleWithTransactionGroups, err := handler.authz.GetWithTransactionGroups(ctx, valuer.MustNewUUID(claims.OrgID), roleID)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
render.Success(rw, http.StatusOK, roleWithTransactionGroups)
|
|
}
|
|
|
|
func (handler *handler) List(rw http.ResponseWriter, r *http.Request) {
|
|
ctx := r.Context()
|
|
claims, err := authtypes.ClaimsFromContext(ctx)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
roles, err := handler.authz.List(ctx, valuer.MustNewUUID(claims.OrgID))
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
render.Success(rw, http.StatusOK, roles)
|
|
}
|
|
|
|
func (handler *handler) Update(rw http.ResponseWriter, r *http.Request) {
|
|
ctx := r.Context()
|
|
claims, err := authtypes.ClaimsFromContext(ctx)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
id, err := valuer.NewUUID(coretypes.Param(r, "id"))
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
req := new(authtypes.UpdatableRole)
|
|
if err := binding.JSON.BindBody(r.Body, req); err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
role, err := handler.authz.Get(ctx, valuer.MustNewUUID(claims.OrgID), id)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
roleWithTransactionGroups := authtypes.MakeRoleWithTransactionGroups(role, nil)
|
|
err = roleWithTransactionGroups.Update(req.Description, req.TransactionGroups)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
err = handler.authz.Update(ctx, valuer.MustNewUUID(claims.OrgID), roleWithTransactionGroups)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
render.Success(rw, http.StatusNoContent, nil)
|
|
}
|
|
|
|
func (handler *handler) Delete(rw http.ResponseWriter, r *http.Request) {
|
|
ctx := r.Context()
|
|
claims, err := authtypes.ClaimsFromContext(ctx)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
id, err := valuer.NewUUID(coretypes.Param(r, "id"))
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
err = handler.authz.Delete(ctx, valuer.MustNewUUID(claims.OrgID), id)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
render.Success(rw, http.StatusNoContent, nil)
|
|
}
|
|
|
|
func (handler *handler) Check(rw http.ResponseWriter, r *http.Request) {
|
|
ctx := r.Context()
|
|
claims, err := authtypes.ClaimsFromContext(ctx)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
transactions := make([]*authtypes.Transaction, 0)
|
|
if err := binding.JSON.BindBody(r.Body, &transactions); err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
orgID := valuer.MustNewUUID(claims.OrgID)
|
|
subject, err := authtypes.NewSubject(coretypes.NewResourceUser(), claims.UserID, orgID, nil)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
results, err := handler.authz.CheckTransactions(ctx, subject, orgID, transactions)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
render.Success(rw, http.StatusOK, authtypes.NewGettableTransaction(results))
|
|
}
|