fleet/server/service/user_roles.go
Martin Angers 4f4185372d
Add support for context in datastore/mysql layer (#1962)
This is just to pass down the context to the datastore layer, it doesn't
use it just yet - this will be in a follow-up PR.
2021-09-14 08:11:07 -04:00

86 lines
2.2 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) (interface{}, 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 {
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
}