mirror of
https://github.com/empayre/fleet.git
synced 2024-11-06 08:55:24 +00:00
666ae8d787
this helps consumer of the datastore method handle the not found scenario better and ensures we always return a 4xx code by default if we can't find a matching team. seems like calls to this method were special-cased everywhere except in the apply user roles endpoint, where we returned a `500` status code if we couldn't find a team.
92 lines
2.3 KiB
Go
92 lines
2.3 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/fleetdm/fleet/v4/server/fleet"
|
|
"gopkg.in/guregu/null.v3"
|
|
)
|
|
|
|
type applyUserRoleSpecsRequest struct {
|
|
Spec *fleet.UsersRoleSpec `json:"spec"`
|
|
}
|
|
|
|
type applyUserRoleSpecsResponse struct {
|
|
Err error `json:"error,omitempty"`
|
|
}
|
|
|
|
func (r applyUserRoleSpecsResponse) error() error { return r.Err }
|
|
|
|
func applyUserRoleSpecsEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (errorer, error) {
|
|
req := request.(*applyUserRoleSpecsRequest)
|
|
err := svc.ApplyUserRolesSpecs(ctx, *req.Spec)
|
|
if err != nil {
|
|
return applyUserRoleSpecsResponse{Err: err}, nil
|
|
}
|
|
return applyUserRoleSpecsResponse{}, nil
|
|
}
|
|
|
|
func (svc *Service) ApplyUserRolesSpecs(ctx context.Context, specs fleet.UsersRoleSpec) error {
|
|
if err := svc.authz.Authorize(ctx, &fleet.User{}, fleet.ActionWrite); err != nil {
|
|
return err
|
|
}
|
|
|
|
var users []*fleet.User
|
|
for email, spec := range specs.Roles {
|
|
user, err := svc.ds.UserByEmail(ctx, email)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// If an admin is downgraded, make sure there is at least one other admin
|
|
err = svc.checkAtLeastOneAdmin(ctx, user, spec, email)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
user.GlobalRole = spec.GlobalRole
|
|
var teams []fleet.UserTeam
|
|
for _, team := range spec.Teams {
|
|
t, err := svc.ds.TeamByName(ctx, team.Name)
|
|
if err != nil {
|
|
if fleet.IsNotFound(err) {
|
|
return &fleet.BadRequestError{
|
|
Message: err.Error(),
|
|
InternalErr: err,
|
|
}
|
|
}
|
|
return err
|
|
}
|
|
teams = append(teams, fleet.UserTeam{
|
|
Team: *t,
|
|
Role: team.Role,
|
|
})
|
|
}
|
|
user.Teams = teams
|
|
users = append(users, user)
|
|
}
|
|
|
|
return svc.ds.SaveUsers(ctx, users)
|
|
}
|
|
|
|
func (svc *Service) checkAtLeastOneAdmin(ctx context.Context, user *fleet.User, spec *fleet.UserRoleSpec, email string) error {
|
|
if null.StringFromPtr(user.GlobalRole).ValueOrZero() == fleet.RoleAdmin &&
|
|
null.StringFromPtr(spec.GlobalRole).ValueOrZero() != fleet.RoleAdmin {
|
|
users, err := svc.ds.ListUsers(ctx, fleet.UserListOptions{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
adminsExceptCurrent := 0
|
|
for _, u := range users {
|
|
if u.Email == email {
|
|
continue
|
|
}
|
|
if null.StringFromPtr(u.GlobalRole).ValueOrZero() == fleet.RoleAdmin {
|
|
adminsExceptCurrent++
|
|
}
|
|
}
|
|
if adminsExceptCurrent == 0 {
|
|
return fleet.NewError(fleet.ErrNoOneAdminNeeded, "You need at least one admin")
|
|
}
|
|
}
|
|
return nil
|
|
}
|