2021-08-24 20:24:52 +00:00
|
|
|
package service
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2021-11-24 17:16:42 +00:00
|
|
|
"errors"
|
|
|
|
"fmt"
|
2021-08-24 20:24:52 +00:00
|
|
|
|
2021-11-22 14:13:26 +00:00
|
|
|
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
|
2021-11-24 17:16:42 +00:00
|
|
|
"github.com/fleetdm/fleet/v4/server/contexts/viewer"
|
2021-08-24 20:24:52 +00:00
|
|
|
"github.com/fleetdm/fleet/v4/server/fleet"
|
2021-11-24 17:16:42 +00:00
|
|
|
"github.com/fleetdm/fleet/v4/server/ptr"
|
2021-08-24 20:24:52 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Add
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
type globalPolicyRequest struct {
|
2021-11-24 17:16:42 +00:00
|
|
|
QueryID *uint `json:"query_id"`
|
|
|
|
Query string `json:"query"`
|
|
|
|
Name string `json:"name"`
|
|
|
|
Description string `json:"description"`
|
|
|
|
Resolution string `json:"resolution"`
|
2021-12-10 16:55:49 +00:00
|
|
|
Platform string `json:"platform"`
|
2021-08-24 20:24:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type globalPolicyResponse struct {
|
|
|
|
Policy *fleet.Policy `json:"policy,omitempty"`
|
|
|
|
Err error `json:"error,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r globalPolicyResponse) error() error { return r.Err }
|
|
|
|
|
|
|
|
func globalPolicyEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (interface{}, error) {
|
|
|
|
req := request.(*globalPolicyRequest)
|
2021-11-24 17:16:42 +00:00
|
|
|
resp, err := svc.NewGlobalPolicy(ctx, fleet.PolicyPayload{
|
|
|
|
QueryID: req.QueryID,
|
|
|
|
Query: req.Query,
|
|
|
|
Name: req.Name,
|
|
|
|
Description: req.Description,
|
|
|
|
Resolution: req.Resolution,
|
2021-12-10 16:55:49 +00:00
|
|
|
Platform: req.Platform,
|
2021-11-24 17:16:42 +00:00
|
|
|
})
|
2021-08-24 20:24:52 +00:00
|
|
|
if err != nil {
|
|
|
|
return globalPolicyResponse{Err: err}, nil
|
|
|
|
}
|
|
|
|
return globalPolicyResponse{Policy: resp}, nil
|
|
|
|
}
|
|
|
|
|
2021-11-24 17:16:42 +00:00
|
|
|
func (svc Service) NewGlobalPolicy(ctx context.Context, p fleet.PolicyPayload) (*fleet.Policy, error) {
|
2021-08-24 20:24:52 +00:00
|
|
|
if err := svc.authz.Authorize(ctx, &fleet.Policy{}, fleet.ActionWrite); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-11-24 17:16:42 +00:00
|
|
|
vc, ok := viewer.FromContext(ctx)
|
|
|
|
if !ok {
|
|
|
|
return nil, errors.New("user must be authenticated to create team policies")
|
|
|
|
}
|
|
|
|
if err := p.Verify(); err != nil {
|
|
|
|
return nil, &badRequestError{
|
|
|
|
message: fmt.Sprintf("policy payload verification: %s", err),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
policy, err := svc.ds.NewGlobalPolicy(ctx, ptr.Uint(vc.UserID()), p)
|
|
|
|
if err != nil {
|
|
|
|
return nil, ctxerr.Wrap(ctx, err, "storing policy")
|
|
|
|
}
|
|
|
|
return policy, nil
|
2021-08-24 20:24:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// List
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
type listGlobalPoliciesResponse struct {
|
|
|
|
Policies []*fleet.Policy `json:"policies,omitempty"`
|
|
|
|
Err error `json:"error,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r listGlobalPoliciesResponse) error() error { return r.Err }
|
|
|
|
|
|
|
|
func listGlobalPoliciesEndpoint(ctx context.Context, _ interface{}, svc fleet.Service) (interface{}, error) {
|
|
|
|
resp, err := svc.ListGlobalPolicies(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return listGlobalPoliciesResponse{Err: err}, nil
|
|
|
|
}
|
|
|
|
return listGlobalPoliciesResponse{Policies: resp}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (svc Service) ListGlobalPolicies(ctx context.Context) ([]*fleet.Policy, error) {
|
|
|
|
if err := svc.authz.Authorize(ctx, &fleet.Policy{}, fleet.ActionRead); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-09-14 12:11:07 +00:00
|
|
|
return svc.ds.ListGlobalPolicies(ctx)
|
2021-08-24 20:24:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Get by id
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
type getPolicyByIDRequest struct {
|
|
|
|
PolicyID uint `url:"policy_id"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type getPolicyByIDResponse struct {
|
|
|
|
Policy *fleet.Policy `json:"policy"`
|
|
|
|
Err error `json:"error,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r getPolicyByIDResponse) error() error { return r.Err }
|
|
|
|
|
|
|
|
func getPolicyByIDEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (interface{}, error) {
|
|
|
|
req := request.(*getPolicyByIDRequest)
|
|
|
|
policy, err := svc.GetPolicyByIDQueries(ctx, req.PolicyID)
|
|
|
|
if err != nil {
|
|
|
|
return getPolicyByIDResponse{Err: err}, nil
|
|
|
|
}
|
|
|
|
return getPolicyByIDResponse{Policy: policy}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (svc Service) GetPolicyByIDQueries(ctx context.Context, policyID uint) (*fleet.Policy, error) {
|
|
|
|
if err := svc.authz.Authorize(ctx, &fleet.Policy{}, fleet.ActionRead); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-09-14 12:11:07 +00:00
|
|
|
policy, err := svc.ds.Policy(ctx, policyID)
|
2021-08-24 20:24:52 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return policy, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Delete
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
type deleteGlobalPoliciesRequest struct {
|
|
|
|
IDs []uint `json:"ids"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type deleteGlobalPoliciesResponse struct {
|
|
|
|
Deleted []uint `json:"deleted,omitempty"`
|
|
|
|
Err error `json:"error,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r deleteGlobalPoliciesResponse) error() error { return r.Err }
|
|
|
|
|
|
|
|
func deleteGlobalPoliciesEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (interface{}, error) {
|
|
|
|
req := request.(*deleteGlobalPoliciesRequest)
|
|
|
|
resp, err := svc.DeleteGlobalPolicies(ctx, req.IDs)
|
|
|
|
if err != nil {
|
|
|
|
return deleteGlobalPoliciesResponse{Err: err}, nil
|
|
|
|
}
|
|
|
|
return deleteGlobalPoliciesResponse{Deleted: resp}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (svc Service) DeleteGlobalPolicies(ctx context.Context, ids []uint) ([]uint, error) {
|
|
|
|
if err := svc.authz.Authorize(ctx, &fleet.Policy{}, fleet.ActionWrite); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-11-24 17:16:42 +00:00
|
|
|
if len(ids) == 0 {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
ids, err := svc.ds.DeleteGlobalPolicies(ctx, ids)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return ids, nil
|
|
|
|
}
|
2021-08-24 20:24:52 +00:00
|
|
|
|
2021-11-24 17:16:42 +00:00
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Modify
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
type modifyGlobalPolicyRequest struct {
|
|
|
|
PolicyID uint `url:"policy_id"`
|
|
|
|
fleet.ModifyPolicyPayload
|
|
|
|
}
|
|
|
|
|
|
|
|
type modifyGlobalPolicyResponse struct {
|
|
|
|
Policy *fleet.Policy `json:"policy,omitempty"`
|
|
|
|
Err error `json:"error,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r modifyGlobalPolicyResponse) error() error { return r.Err }
|
|
|
|
|
|
|
|
func modifyGlobalPolicyEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (interface{}, error) {
|
|
|
|
req := request.(*modifyGlobalPolicyRequest)
|
|
|
|
resp, err := svc.ModifyGlobalPolicy(ctx, req.PolicyID, req.ModifyPolicyPayload)
|
|
|
|
if err != nil {
|
|
|
|
return modifyGlobalPolicyResponse{Err: err}, nil
|
|
|
|
}
|
|
|
|
return modifyGlobalPolicyResponse{Policy: resp}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (svc Service) ModifyGlobalPolicy(ctx context.Context, id uint, p fleet.ModifyPolicyPayload) (*fleet.Policy, error) {
|
|
|
|
return svc.modifyPolicy(ctx, nil, id, p)
|
2021-08-24 20:24:52 +00:00
|
|
|
}
|
2021-10-15 10:34:11 +00:00
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Apply Spec
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
type applyPolicySpecsRequest struct {
|
|
|
|
Specs []*fleet.PolicySpec `json:"specs"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type applyPolicySpecsResponse struct {
|
|
|
|
Err error `json:"error,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r applyPolicySpecsResponse) error() error { return r.Err }
|
|
|
|
|
|
|
|
func applyPolicySpecsEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (interface{}, error) {
|
|
|
|
req := request.(*applyPolicySpecsRequest)
|
|
|
|
err := svc.ApplyPolicySpecs(ctx, req.Specs)
|
|
|
|
if err != nil {
|
|
|
|
return applyPolicySpecsResponse{Err: err}, nil
|
|
|
|
}
|
|
|
|
return applyPolicySpecsResponse{}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (svc Service) ApplyPolicySpecs(ctx context.Context, policies []*fleet.PolicySpec) error {
|
|
|
|
checkGlobalPolicyAuth := false
|
|
|
|
for _, policy := range policies {
|
2021-11-24 17:16:42 +00:00
|
|
|
if err := policy.Verify(); err != nil {
|
|
|
|
return ctxerr.Wrap(ctx, err, "verifying spec")
|
|
|
|
}
|
2021-10-15 10:34:11 +00:00
|
|
|
if policy.Team != "" {
|
|
|
|
team, err := svc.ds.TeamByName(ctx, policy.Team)
|
|
|
|
if err != nil {
|
2021-11-22 14:13:26 +00:00
|
|
|
return ctxerr.Wrap(ctx, err, "getting team by name")
|
2021-10-15 10:34:11 +00:00
|
|
|
}
|
2021-11-24 17:16:42 +00:00
|
|
|
if err := svc.authz.Authorize(ctx, &fleet.Policy{
|
|
|
|
PolicyData: fleet.PolicyData{
|
|
|
|
TeamID: &team.ID,
|
|
|
|
},
|
|
|
|
}, fleet.ActionWrite); err != nil {
|
2021-10-15 10:34:11 +00:00
|
|
|
return err
|
|
|
|
}
|
2021-11-24 17:16:42 +00:00
|
|
|
} else {
|
|
|
|
checkGlobalPolicyAuth = true
|
2021-10-15 10:34:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if checkGlobalPolicyAuth {
|
|
|
|
if err := svc.authz.Authorize(ctx, &fleet.Policy{}, fleet.ActionWrite); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2021-11-24 17:16:42 +00:00
|
|
|
vc, ok := viewer.FromContext(ctx)
|
|
|
|
if !ok {
|
|
|
|
return errors.New("user must be authenticated to apply policies")
|
|
|
|
}
|
|
|
|
if err := svc.ds.ApplyPolicySpecs(ctx, vc.UserID(), policies); err != nil {
|
|
|
|
return ctxerr.Wrap(ctx, err, "applying policy specs")
|
|
|
|
}
|
|
|
|
return nil
|
2021-10-15 10:34:11 +00:00
|
|
|
}
|