influxdb/authorizer/notification_endpoint.go

165 lines
5.7 KiB
Go

package authorizer
import (
"context"
"github.com/influxdata/influxdb"
)
var _ influxdb.NotificationEndpointService = (*NotificationEndpointService)(nil)
// NotificationEndpointService wraps a influxdb.NotificationEndpointService and authorizes actions
// against it appropriately.
type NotificationEndpointService struct {
s influxdb.NotificationEndpointService
influxdb.UserResourceMappingService
influxdb.OrganizationService
}
// NewNotificationEndpointService constructs an instance of an authorizing notification endpoint serivce.
func NewNotificationEndpointService(
s influxdb.NotificationEndpointService,
urm influxdb.UserResourceMappingService,
org influxdb.OrganizationService,
) *NotificationEndpointService {
return &NotificationEndpointService{
s: s,
UserResourceMappingService: urm,
OrganizationService: org,
}
}
func newNotificationEndpointPermission(a influxdb.Action, orgID, id influxdb.ID) (*influxdb.Permission, error) {
return influxdb.NewPermissionAtID(id, a, influxdb.NotificationEndpointResourceType, orgID)
}
func authorizeReadNotificationEndpoint(ctx context.Context, orgID, id influxdb.ID) error {
p, err := newNotificationEndpointPermission(influxdb.ReadAction, orgID, id)
if err != nil {
return err
}
if err := IsAllowed(ctx, *p); err != nil {
return err
}
return nil
}
func authorizeWriteNotificationEndpoint(ctx context.Context, orgID, id influxdb.ID) error {
p, err := newNotificationEndpointPermission(influxdb.WriteAction, orgID, id)
if err != nil {
return err
}
if err := IsAllowed(ctx, *p); err != nil {
return err
}
return nil
}
// FindNotificationEndpointByID checks to see if the authorizer on context has read access to the id provided.
func (s *NotificationEndpointService) FindNotificationEndpointByID(ctx context.Context, id influxdb.ID) (influxdb.NotificationEndpoint, error) {
edp, err := s.s.FindNotificationEndpointByID(ctx, id)
if err != nil {
return nil, err
}
if err := authorizeReadNotificationEndpoint(ctx, edp.GetOrgID(), edp.GetID()); err != nil {
return nil, err
}
return edp, nil
}
// FindNotificationEndpoints retrieves all notification endpoints that match the provided filter and then filters the list down to only the resources that are authorized.
func (s *NotificationEndpointService) FindNotificationEndpoints(ctx context.Context, filter influxdb.NotificationEndpointFilter, opt ...influxdb.FindOptions) ([]influxdb.NotificationEndpoint, int, error) {
// TODO: This is a temporary fix as to not fetch the entire collection when no filter is provided.
if !filter.UserID.Valid() && filter.OrgID == nil {
return nil, 0, &influxdb.Error{
Code: influxdb.EUnauthorized,
Msg: "cannot process a request without a org or user filter",
}
}
// TODO: we'll likely want to push this operation into the database eventually since fetching the whole list of data
// will likely be expensive.
edps, _, err := s.s.FindNotificationEndpoints(ctx, filter, opt...)
if err != nil {
return nil, 0, err
}
// This filters without allocating
// https://github.com/golang/go/wiki/SliceTricks#filtering-without-allocating
endpoints := edps[:0]
for _, edp := range edps {
err := authorizeReadNotificationEndpoint(ctx, edp.GetOrgID(), edp.GetID())
if err != nil && influxdb.ErrorCode(err) != influxdb.EUnauthorized {
return nil, 0, err
}
if influxdb.ErrorCode(err) == influxdb.EUnauthorized {
continue
}
endpoints = append(endpoints, edp)
}
return endpoints, len(endpoints), nil
}
// CreateNotificationEndpoint checks to see if the authorizer on context has write access to the global notification endpoint resource.
func (s *NotificationEndpointService) CreateNotificationEndpoint(ctx context.Context, edp influxdb.NotificationEndpoint, userID influxdb.ID) error {
p, err := influxdb.NewPermission(influxdb.WriteAction, influxdb.NotificationEndpointResourceType, edp.GetOrgID())
if err != nil {
return err
}
if err := IsAllowed(ctx, *p); err != nil {
return err
}
return s.s.CreateNotificationEndpoint(ctx, edp, userID)
}
// UpdateNotificationEndpoint checks to see if the authorizer on context has write access to the notification endpoint provided.
func (s *NotificationEndpointService) UpdateNotificationEndpoint(ctx context.Context, id influxdb.ID, upd influxdb.NotificationEndpoint, userID influxdb.ID) (influxdb.NotificationEndpoint, error) {
edp, err := s.FindNotificationEndpointByID(ctx, id)
if err != nil {
return nil, err
}
if err := authorizeWriteNotificationEndpoint(ctx, edp.GetOrgID(), edp.GetID()); err != nil {
return nil, err
}
return s.s.UpdateNotificationEndpoint(ctx, id, upd, userID)
}
// PatchNotificationEndpoint checks to see if the authorizer on context has write access to the notification endpoint provided.
func (s *NotificationEndpointService) PatchNotificationEndpoint(ctx context.Context, id influxdb.ID, upd influxdb.NotificationEndpointUpdate) (influxdb.NotificationEndpoint, error) {
edp, err := s.FindNotificationEndpointByID(ctx, id)
if err != nil {
return nil, err
}
if err := authorizeWriteNotificationEndpoint(ctx, edp.GetOrgID(), edp.GetID()); err != nil {
return nil, err
}
return s.s.PatchNotificationEndpoint(ctx, id, upd)
}
// DeleteNotificationEndpoint checks to see if the authorizer on context has write access to the notification endpoint provided.
func (s *NotificationEndpointService) DeleteNotificationEndpoint(ctx context.Context, id influxdb.ID) ([]influxdb.SecretField, influxdb.ID, error) {
edp, err := s.FindNotificationEndpointByID(ctx, id)
if err != nil {
return nil, 0, err
}
if err := authorizeWriteNotificationEndpoint(ctx, edp.GetOrgID(), edp.GetID()); err != nil {
return nil, 0, err
}
return s.s.DeleteNotificationEndpoint(ctx, id)
}