95 lines
3.2 KiB
Go
95 lines
3.2 KiB
Go
package permissionsimp
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"github.com/tech/sendico/pkg/api/http/response"
|
|
"github.com/tech/sendico/pkg/merrors"
|
|
"github.com/tech/sendico/pkg/model"
|
|
"github.com/tech/sendico/pkg/mservice"
|
|
"github.com/tech/sendico/server/interface/api/srequest"
|
|
"github.com/tech/sendico/server/interface/api/sresponse"
|
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
func (a *PermissionsAPI) changePolicies(r *http.Request, account *model.Account, _ *sresponse.TokenData) http.HandlerFunc {
|
|
var req srequest.ChangePolicies
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
a.logger.Warn("Failed to decode role policies change request", zap.Error(err))
|
|
return response.BadPayload(a.logger, mservice.Roles, err)
|
|
}
|
|
if req.Add != nil && req.Remove != nil {
|
|
for _, addItem := range *req.Add {
|
|
for _, removeItem := range *req.Remove {
|
|
if addItem == removeItem {
|
|
a.logger.Debug("Duplicate policies found, rejecting policies update request", zap.Any("add", &addItem), zap.Any("remove", &removeItem))
|
|
return response.BadRequest(a.logger, a.Name(), "invalid_policies_change_request", "duplicate policies found in 'add' and 'remove' fields")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if _, err := a.tf.CreateTransaction().Execute(r.Context(), func(ctx context.Context) (any, error) {
|
|
return a.changePoliciesImp(ctx, account, &req)
|
|
}); err != nil {
|
|
a.logger.Debug("Rolling policies changes back", zap.Error(err))
|
|
return response.Auto(a.logger, a.Name(), err)
|
|
}
|
|
|
|
return response.Success(a.logger)
|
|
}
|
|
|
|
func (a *PermissionsAPI) changePoliciesImp(
|
|
ctx context.Context,
|
|
account *model.Account,
|
|
req *srequest.ChangePolicies,
|
|
) (any, error) {
|
|
// helper that runs through each change-item, enforces the right action,
|
|
// and then calls apply(item) if enforcement passes.
|
|
handle := func(items *[]model.RolePolicy, action model.Action, opName string, apply func(context.Context, *model.RolePolicy) error) error {
|
|
for _, it := range *items {
|
|
// 1) permission check
|
|
ok, err := a.enforcer.Enforce(ctx, a.policiesPermissionRef, account.ID, it.OrganizationRef, primitive.NilObjectID, action)
|
|
if err != nil {
|
|
a.logger.Warn(fmt.Sprintf("failed to enforce permission while %s policy", opName), zap.Error(err), zap.Any(opName, &it))
|
|
return err
|
|
}
|
|
if !ok {
|
|
a.logger.Debug(fmt.Sprintf("policy %s denied", opName))
|
|
return merrors.AccessDenied(mservice.Policies, string(action), primitive.NilObjectID)
|
|
}
|
|
|
|
// 2) perform the add/remove
|
|
if err := apply(ctx, &it); err != nil {
|
|
a.logger.Warn(fmt.Sprintf("failed to %s role policy", opName), zap.Error(err), zap.Any("policy", &it))
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// REMOVE
|
|
if req.Remove != nil {
|
|
if err := handle(req.Remove, model.ActionDelete, "remove", func(ctx context.Context, it *model.RolePolicy) error {
|
|
return a.auth.Permission().RevokeFromRole(ctx, it)
|
|
}); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
// ADD
|
|
if req.Add != nil {
|
|
if err := handle(req.Add, model.ActionCreate, "add", func(ctx context.Context, it *model.RolePolicy) error {
|
|
return a.auth.Permission().GrantToRole(ctx, it)
|
|
}); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
return nil, nil
|
|
}
|