feat(annotations): authorization service (#21665)
* feat(annotations): added authz service for annotations and streams * fix: tests and adjustments * chore: misc cleanup * chore: update number in authz comment Co-authored-by: Daniel Moran <danxmoran@gmail.com> * chore: update number in authz comment Co-authored-by: Daniel Moran <danxmoran@gmail.com> * chore: update number in authz comment Co-authored-by: Daniel Moran <danxmoran@gmail.com> * fix: address review comments * feat: added post-list filter for fine-grained auth Co-authored-by: Daniel Moran <danxmoran@gmail.com>pull/21675/head
parent
40c7d69415
commit
8ee59f4bf4
|
@ -68,9 +68,9 @@ type AnnotationService interface {
|
|||
// CreateAnnotations creates annotations.
|
||||
CreateAnnotations(ctx context.Context, orgID platform.ID, create []AnnotationCreate) ([]AnnotationEvent, error)
|
||||
// ListAnnotations lists all annotations matching the filter.
|
||||
ListAnnotations(ctx context.Context, orgID platform.ID, filter AnnotationListFilter) (ReadAnnotations, error)
|
||||
ListAnnotations(ctx context.Context, orgID platform.ID, filter AnnotationListFilter) ([]StoredAnnotation, error)
|
||||
// GetAnnotation gets an annotation by id.
|
||||
GetAnnotation(ctx context.Context, id platform.ID) (*AnnotationEvent, error)
|
||||
GetAnnotation(ctx context.Context, id platform.ID) (*StoredAnnotation, error)
|
||||
// DeleteAnnotations deletes annotations matching the filter.
|
||||
DeleteAnnotations(ctx context.Context, orgID platform.ID, delete AnnotationDeleteFilter) error
|
||||
// DeleteAnnotation deletes an annotation by id.
|
||||
|
@ -79,13 +79,16 @@ type AnnotationService interface {
|
|||
UpdateAnnotation(ctx context.Context, id platform.ID, update AnnotationCreate) (*AnnotationEvent, error)
|
||||
|
||||
// ListStreams lists all streams matching the filter.
|
||||
ListStreams(ctx context.Context, orgID platform.ID, filter StreamListFilter) ([]ReadStream, error)
|
||||
ListStreams(ctx context.Context, orgID platform.ID, filter StreamListFilter) ([]StoredStream, error)
|
||||
// CreateOrUpdateStream creates or updates the matching stream by name.
|
||||
CreateOrUpdateStream(ctx context.Context, stream Stream) (*ReadStream, error)
|
||||
CreateOrUpdateStream(ctx context.Context, orgID platform.ID, stream Stream) (*ReadStream, error)
|
||||
// GetStream gets a stream by id. Currently this is only used for authorization, and there are no
|
||||
// API routes for getting a single stream by ID.
|
||||
GetStream(ctx context.Context, id platform.ID) (*StoredStream, error)
|
||||
// UpdateStream updates the stream by the ID.
|
||||
UpdateStream(ctx context.Context, id platform.ID, stream Stream) (*ReadStream, error)
|
||||
// DeleteStreams deletes one or more streams by name.
|
||||
DeleteStreams(ctx context.Context, delete BasicStream) error
|
||||
DeleteStreams(ctx context.Context, orgID platform.ID, delete BasicStream) error
|
||||
// DeleteStreamByID deletes the stream metadata by id.
|
||||
DeleteStreamByID(ctx context.Context, id platform.ID) error
|
||||
}
|
||||
|
@ -116,7 +119,7 @@ type StoredAnnotation struct {
|
|||
Message string `db:"message"` // Message is a longer description of the annotated event.
|
||||
Stickers []string `db:"stickers"` // Stickers are additional labels to group annotations by.
|
||||
Duration string `db:"duration"` // Duration is the time range (with zone) of an annotated event.
|
||||
Lower string `db:"lower"` // Lower is the time an annotated event beings.
|
||||
Lower string `db:"lower"` // Lower is the time an annotated event begins.
|
||||
Upper string `db:"upper"` // Upper is the time an annotated event ends.
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package transport
|
|||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
|
@ -65,7 +66,13 @@ func (h *AnnotationHandler) handleGetAnnotations(w http.ResponseWriter, r *http.
|
|||
return
|
||||
}
|
||||
|
||||
l, err := h.annotationService.ListAnnotations(ctx, *o, *f)
|
||||
s, err := h.annotationService.ListAnnotations(ctx, *o, *f)
|
||||
if err != nil {
|
||||
h.api.Err(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
l, err := storedAnnotationsToReadAnnotations(s)
|
||||
if err != nil {
|
||||
h.api.Err(w, r, err)
|
||||
return
|
||||
|
@ -106,13 +113,19 @@ func (h *AnnotationHandler) handleGetAnnotation(w http.ResponseWriter, r *http.R
|
|||
return
|
||||
}
|
||||
|
||||
a, err := h.annotationService.GetAnnotation(ctx, *id)
|
||||
s, err := h.annotationService.GetAnnotation(ctx, *id)
|
||||
if err != nil {
|
||||
h.api.Err(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
h.api.Respond(w, r, http.StatusOK, a)
|
||||
c, err := storedAnnotationToEvent(s)
|
||||
if err != nil {
|
||||
h.api.Err(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
h.api.Respond(w, r, http.StatusOK, c)
|
||||
}
|
||||
|
||||
func (h *AnnotationHandler) handleDeleteAnnotation(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -234,3 +247,68 @@ func decodeUpdateAnnotationRequest(r *http.Request) (*influxdb.AnnotationCreate,
|
|||
|
||||
return u, nil
|
||||
}
|
||||
|
||||
func storedAnnotationsToReadAnnotations(s []influxdb.StoredAnnotation) (influxdb.ReadAnnotations, error) {
|
||||
r := influxdb.ReadAnnotations{}
|
||||
|
||||
for _, val := range s {
|
||||
stickers, err := stickerSliceToMap(val.Stickers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r[val.StreamTag] = append(r[val.StreamTag], influxdb.ReadAnnotation{
|
||||
ID: val.ID,
|
||||
Summary: val.Summary,
|
||||
Message: val.Message,
|
||||
Stickers: stickers,
|
||||
StartTime: val.Lower,
|
||||
EndTime: val.Upper,
|
||||
})
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func storedAnnotationToEvent(s *influxdb.StoredAnnotation) (*influxdb.AnnotationEvent, error) {
|
||||
st, err := tStringToPointer(s.Lower)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
et, err := tStringToPointer(s.Upper)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stickers, err := stickerSliceToMap(s.Stickers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &influxdb.AnnotationEvent{
|
||||
ID: s.ID,
|
||||
AnnotationCreate: influxdb.AnnotationCreate{
|
||||
StreamTag: s.StreamTag,
|
||||
Summary: s.Summary,
|
||||
Message: s.Message,
|
||||
Stickers: stickers,
|
||||
EndTime: et,
|
||||
StartTime: st,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func stickerSliceToMap(stickers []string) (map[string]string, error) {
|
||||
stickerMap := map[string]string{}
|
||||
|
||||
for i := range stickers {
|
||||
sticks := strings.SplitN(stickers[i], "=", 2)
|
||||
if len(sticks) < 2 {
|
||||
return nil, invalidStickerError(stickers[i])
|
||||
}
|
||||
stickerMap[sticks[0]] = sticks[1]
|
||||
}
|
||||
|
||||
return stickerMap, nil
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@ var (
|
|||
testCreateAnnotation = influxdb.AnnotationCreate{
|
||||
StreamTag: "sometag",
|
||||
Summary: "testing the api",
|
||||
Message: "stored annotation message",
|
||||
Stickers: map[string]string{"val1": "sticker1", "val2": "sticker2"},
|
||||
EndTime: &now,
|
||||
StartTime: &now,
|
||||
}
|
||||
|
@ -32,6 +34,31 @@ var (
|
|||
testReadAnnotation2 = influxdb.ReadAnnotation{
|
||||
ID: *influxdbtesting.IDPtr(2),
|
||||
}
|
||||
|
||||
testStoredAnnotation = influxdb.StoredAnnotation{
|
||||
ID: *id,
|
||||
OrgID: *orgID,
|
||||
StreamID: *influxdbtesting.IDPtr(3),
|
||||
StreamTag: "sometag",
|
||||
Summary: "testing the api",
|
||||
Message: "stored annotation message",
|
||||
Stickers: []string{"val1=sticker1", "val2=sticker2"},
|
||||
Lower: now.Format(time.RFC3339),
|
||||
Upper: now.Format(time.RFC3339),
|
||||
}
|
||||
|
||||
testReadAnnotations = influxdb.ReadAnnotations{
|
||||
"sometag": []influxdb.ReadAnnotation{
|
||||
{
|
||||
ID: testStoredAnnotation.ID,
|
||||
Summary: testStoredAnnotation.Summary,
|
||||
Message: testStoredAnnotation.Message,
|
||||
Stickers: map[string]string{"val1": "sticker1", "val2": "sticker2"},
|
||||
EndTime: testStoredAnnotation.Lower,
|
||||
StartTime: testStoredAnnotation.Upper,
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func TestAnnotationRouter(t *testing.T) {
|
||||
|
@ -72,9 +99,15 @@ func TestAnnotationRouter(t *testing.T) {
|
|||
EndTime: &now,
|
||||
},
|
||||
}).
|
||||
Return(influxdb.ReadAnnotations{
|
||||
"stream1": []influxdb.ReadAnnotation{testReadAnnotation1},
|
||||
"stream2": []influxdb.ReadAnnotation{testReadAnnotation2},
|
||||
Return([]influxdb.StoredAnnotation{
|
||||
{
|
||||
ID: testReadAnnotation1.ID,
|
||||
StreamTag: "stream1",
|
||||
},
|
||||
{
|
||||
ID: testReadAnnotation2.ID,
|
||||
StreamTag: "stream2",
|
||||
},
|
||||
}, nil)
|
||||
|
||||
res := doTestRequest(t, req, http.StatusOK, true)
|
||||
|
@ -143,7 +176,7 @@ func TestAnnotationRouter(t *testing.T) {
|
|||
|
||||
svc.EXPECT().
|
||||
GetAnnotation(gomock.Any(), *id).
|
||||
Return(&testEvent, nil)
|
||||
Return(&testStoredAnnotation, nil)
|
||||
|
||||
res := doTestRequest(t, req, http.StatusOK, true)
|
||||
|
||||
|
@ -216,3 +249,55 @@ func TestAnnotationRouter(t *testing.T) {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestStoredAnnotationsToReadAnnotations(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
got, err := storedAnnotationsToReadAnnotations([]influxdb.StoredAnnotation{testStoredAnnotation})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, got, testReadAnnotations)
|
||||
}
|
||||
|
||||
func TestStoredAnnotationToEvent(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
got, err := storedAnnotationToEvent(&testStoredAnnotation)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, got, &testEvent)
|
||||
}
|
||||
|
||||
func TestStickerSliceToMap(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
stickers []string
|
||||
want map[string]string
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
"good stickers",
|
||||
[]string{"good1=val1", "good2=val2"},
|
||||
map[string]string{"good1": "val1", "good2": "val2"},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"bad stickers",
|
||||
[]string{"this is an invalid sticker", "shouldbe=likethis"},
|
||||
nil,
|
||||
invalidStickerError("this is an invalid sticker"),
|
||||
},
|
||||
{
|
||||
"no stickers",
|
||||
[]string{},
|
||||
map[string]string{},
|
||||
nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
got, err := stickerSliceToMap(tt.stickers)
|
||||
require.Equal(t, tt.want, got)
|
||||
require.Equal(t, tt.wantErr, err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package transport
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
|
@ -40,6 +41,13 @@ var (
|
|||
}
|
||||
)
|
||||
|
||||
func invalidStickerError(s string) error {
|
||||
return &errors.Error{
|
||||
Code: errors.EInternal,
|
||||
Msg: fmt.Sprintf("invalid sticker: %q", s),
|
||||
}
|
||||
}
|
||||
|
||||
// AnnotationsHandler is the handler for the annotation service
|
||||
type AnnotationHandler struct {
|
||||
chi.Router
|
||||
|
|
|
@ -28,13 +28,19 @@ func (h *AnnotationHandler) streamsRouter() http.Handler {
|
|||
func (h *AnnotationHandler) handleCreateOrUpdateStream(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
o, err := platform.IDFromString(r.URL.Query().Get("orgID"))
|
||||
if err != nil {
|
||||
h.api.Err(w, r, errBadOrg)
|
||||
return
|
||||
}
|
||||
|
||||
u, err := decodeCreateOrUpdateStreamRequest(r)
|
||||
if err != nil {
|
||||
h.api.Err(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
s, err := h.annotationService.CreateOrUpdateStream(ctx, *u)
|
||||
s, err := h.annotationService.CreateOrUpdateStream(ctx, *o, *u)
|
||||
if err != nil {
|
||||
h.api.Err(w, r, err)
|
||||
return
|
||||
|
@ -58,19 +64,25 @@ func (h *AnnotationHandler) handleGetStreams(w http.ResponseWriter, r *http.Requ
|
|||
return
|
||||
}
|
||||
|
||||
l, err := h.annotationService.ListStreams(ctx, *o, *f)
|
||||
s, err := h.annotationService.ListStreams(ctx, *o, *f)
|
||||
if err != nil {
|
||||
h.api.Err(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
h.api.Respond(w, r, http.StatusOK, l)
|
||||
h.api.Respond(w, r, http.StatusOK, storedStreamsToReadStreams(s))
|
||||
}
|
||||
|
||||
// Delete stream(s) by name, capable of handling a list of names
|
||||
func (h *AnnotationHandler) handleDeleteStreams(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
o, err := platform.IDFromString(r.URL.Query().Get("orgID"))
|
||||
if err != nil {
|
||||
h.api.Err(w, r, errBadOrg)
|
||||
return
|
||||
}
|
||||
|
||||
f, err := decodeDeleteStreamsRequest(r)
|
||||
if err != nil {
|
||||
h.api.Err(w, r, err)
|
||||
|
@ -79,7 +91,7 @@ func (h *AnnotationHandler) handleDeleteStreams(w http.ResponseWriter, r *http.R
|
|||
|
||||
// delete all of the streams according to the filter. annotations associated with the stream
|
||||
// will be deleted by the ON DELETE CASCADE relationship between streams and annotations.
|
||||
if err = h.annotationService.DeleteStreams(ctx, *f); err != nil {
|
||||
if err = h.annotationService.DeleteStreams(ctx, *o, *f); err != nil {
|
||||
h.api.Err(w, r, err)
|
||||
return
|
||||
}
|
||||
|
@ -176,3 +188,19 @@ func decodeDeleteStreamsRequest(r *http.Request) (*influxdb.BasicStream, error)
|
|||
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func storedStreamsToReadStreams(stored []influxdb.StoredStream) []influxdb.ReadStream {
|
||||
r := make([]influxdb.ReadStream, 0, len(stored))
|
||||
|
||||
for _, s := range stored {
|
||||
r = append(r, influxdb.ReadStream{
|
||||
ID: s.ID,
|
||||
Name: s.Name,
|
||||
Description: s.Description,
|
||||
CreatedAt: s.CreatedAt,
|
||||
UpdatedAt: s.UpdatedAt,
|
||||
})
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
|
|
@ -30,6 +30,24 @@ var (
|
|||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
|
||||
testStoredStream1 = influxdb.StoredStream{
|
||||
ID: testReadStream1.ID,
|
||||
OrgID: *orgID,
|
||||
Name: testReadStream1.Name,
|
||||
Description: testReadStream1.Description,
|
||||
CreatedAt: testReadStream1.CreatedAt,
|
||||
UpdatedAt: testReadStream1.UpdatedAt,
|
||||
}
|
||||
|
||||
testStoredStream2 = influxdb.StoredStream{
|
||||
ID: testReadStream2.ID,
|
||||
OrgID: *orgID,
|
||||
Name: testReadStream2.Name,
|
||||
Description: testReadStream2.Description,
|
||||
CreatedAt: testReadStream2.CreatedAt,
|
||||
UpdatedAt: testReadStream2.UpdatedAt,
|
||||
}
|
||||
)
|
||||
|
||||
func TestStreamsRouter(t *testing.T) {
|
||||
|
@ -46,7 +64,7 @@ func TestStreamsRouter(t *testing.T) {
|
|||
req.URL.RawQuery = q.Encode()
|
||||
|
||||
svc.EXPECT().
|
||||
CreateOrUpdateStream(gomock.Any(), testCreateStream).
|
||||
CreateOrUpdateStream(gomock.Any(), *orgID, testCreateStream).
|
||||
Return(testReadStream1, nil)
|
||||
|
||||
res := doTestRequest(t, req, http.StatusOK, true)
|
||||
|
@ -70,8 +88,6 @@ func TestStreamsRouter(t *testing.T) {
|
|||
q.Add("streamIncludes", "stream2")
|
||||
req.URL.RawQuery = q.Encode()
|
||||
|
||||
want := []influxdb.ReadStream{*testReadStream1, *testReadStream2}
|
||||
|
||||
svc.EXPECT().
|
||||
ListStreams(gomock.Any(), *orgID, influxdb.StreamListFilter{
|
||||
StreamIncludes: []string{"stream1", "stream2"},
|
||||
|
@ -80,14 +96,14 @@ func TestStreamsRouter(t *testing.T) {
|
|||
EndTime: &now,
|
||||
},
|
||||
}).
|
||||
Return(want, nil)
|
||||
Return([]influxdb.StoredStream{testStoredStream1, testStoredStream2}, nil)
|
||||
|
||||
res := doTestRequest(t, req, http.StatusOK, true)
|
||||
|
||||
got := []influxdb.ReadStream{}
|
||||
err := json.NewDecoder(res.Body).Decode(&got)
|
||||
require.NoError(t, err)
|
||||
require.ElementsMatch(t, want, got)
|
||||
require.ElementsMatch(t, []influxdb.ReadStream{*testReadStream1, *testReadStream2}, got)
|
||||
})
|
||||
|
||||
t.Run("delete streams (by name) happy path", func(t *testing.T) {
|
||||
|
@ -96,12 +112,13 @@ func TestStreamsRouter(t *testing.T) {
|
|||
|
||||
req := newTestRequest(t, "DELETE", ts.URL+"/streams", nil)
|
||||
q := req.URL.Query()
|
||||
q.Add("orgID", orgStr)
|
||||
q.Add("stream", "stream1")
|
||||
q.Add("stream", "stream2")
|
||||
req.URL.RawQuery = q.Encode()
|
||||
|
||||
svc.EXPECT().
|
||||
DeleteStreams(gomock.Any(), influxdb.BasicStream{
|
||||
DeleteStreams(gomock.Any(), *orgID, influxdb.BasicStream{
|
||||
Names: []string{"stream1", "stream2"},
|
||||
}).
|
||||
Return(nil)
|
||||
|
@ -141,7 +158,7 @@ func TestStreamsRouter(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("invalid org ids return 400 when required", func(t *testing.T) {
|
||||
methods := []string{"GET"}
|
||||
methods := []string{"GET", "PUT", "DELETE"}
|
||||
|
||||
for _, m := range methods {
|
||||
t.Run(m, func(t *testing.T) {
|
||||
|
@ -172,3 +189,10 @@ func TestStreamsRouter(t *testing.T) {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestStoredStreamsToReadStreams(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
got := storedStreamsToReadStreams([]influxdb.StoredStream{testStoredStream1, testStoredStream2})
|
||||
require.Equal(t, got, []influxdb.ReadStream{*testReadStream1, *testReadStream2})
|
||||
}
|
||||
|
|
|
@ -0,0 +1,189 @@
|
|||
package authorizer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/influxdata/influxdb/v2"
|
||||
"github.com/influxdata/influxdb/v2/kit/platform"
|
||||
"github.com/influxdata/influxdb/v2/kit/platform/errors"
|
||||
)
|
||||
|
||||
var _ influxdb.AnnotationService = (*AnnotationService)(nil)
|
||||
|
||||
// AnnotationService wraps an influxdb.AnnotationService and authorizes actions
|
||||
// against it appropriately.
|
||||
type AnnotationService struct {
|
||||
s influxdb.AnnotationService
|
||||
}
|
||||
|
||||
// NewAnnotationService constructs an instance of an authorizing check service
|
||||
func NewAnnotationService(s influxdb.AnnotationService) *AnnotationService {
|
||||
return &AnnotationService{
|
||||
s: s,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateAnnotations checks to see if the authorizer on context has write access for annotations for the provided orgID
|
||||
func (s *AnnotationService) CreateAnnotations(ctx context.Context, orgID platform.ID, create []influxdb.AnnotationCreate) ([]influxdb.AnnotationEvent, error) {
|
||||
if _, _, err := AuthorizeCreate(ctx, influxdb.AnnotationsResourceType, orgID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.s.CreateAnnotations(ctx, orgID, create)
|
||||
}
|
||||
|
||||
// ListAnnotations checks to see if the authorizer on context has read access for annotations for the provided orgID
|
||||
// and then filters the list down to only the resources that are authorized
|
||||
func (s *AnnotationService) ListAnnotations(ctx context.Context, orgID platform.ID, filter influxdb.AnnotationListFilter) ([]influxdb.StoredAnnotation, error) {
|
||||
if _, _, err := AuthorizeOrgReadResource(ctx, influxdb.AnnotationsResourceType, orgID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
as, err := s.s.ListAnnotations(ctx, orgID, filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
as, _, err = AuthorizeFindAnnotations(ctx, as)
|
||||
return as, err
|
||||
}
|
||||
|
||||
// GetAnnotation checks to see if the authorizer on context has read access to the requested annotation
|
||||
func (s *AnnotationService) GetAnnotation(ctx context.Context, id platform.ID) (*influxdb.StoredAnnotation, error) {
|
||||
a, err := s.s.GetAnnotation(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, _, err := AuthorizeRead(ctx, influxdb.AnnotationsResourceType, id, a.OrgID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// DeleteAnnotations checks to see if the authorizer on context has write access to the provided orgID
|
||||
func (s *AnnotationService) DeleteAnnotations(ctx context.Context, orgID platform.ID, delete influxdb.AnnotationDeleteFilter) error {
|
||||
if _, _, err := AuthorizeOrgWriteResource(ctx, influxdb.AnnotationsResourceType, orgID); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.s.DeleteAnnotations(ctx, orgID, delete)
|
||||
}
|
||||
|
||||
// DeleteAnnotation checks to see if the authorizer on context has write access to the requested annotation
|
||||
func (s *AnnotationService) DeleteAnnotation(ctx context.Context, id platform.ID) error {
|
||||
a, err := s.s.GetAnnotation(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, _, err := AuthorizeWrite(ctx, influxdb.AnnotationsResourceType, id, a.OrgID); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.s.DeleteAnnotation(ctx, id)
|
||||
}
|
||||
|
||||
// UpdateAnnotation checks to see if the authorizer on context has write access to the requested annotation
|
||||
func (s *AnnotationService) UpdateAnnotation(ctx context.Context, id platform.ID, update influxdb.AnnotationCreate) (*influxdb.AnnotationEvent, error) {
|
||||
a, err := s.s.GetAnnotation(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, _, err := AuthorizeWrite(ctx, influxdb.AnnotationsResourceType, id, a.OrgID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.s.UpdateAnnotation(ctx, id, update)
|
||||
}
|
||||
|
||||
// ListStreams checks to see if the authorizer on context has read access for streams for the provided orgID
|
||||
// and then filters the list down to only the resources that are authorized
|
||||
func (s *AnnotationService) ListStreams(ctx context.Context, orgID platform.ID, filter influxdb.StreamListFilter) ([]influxdb.StoredStream, error) {
|
||||
if _, _, err := AuthorizeOrgReadResource(ctx, influxdb.AnnotationsResourceType, orgID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ss, err := s.s.ListStreams(ctx, orgID, filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ss, _, err = AuthorizeFindStreams(ctx, ss)
|
||||
return ss, err
|
||||
}
|
||||
|
||||
// GetStream checks to see if the authorizer on context has read access to the requested stream
|
||||
func (s *AnnotationService) GetStream(ctx context.Context, id platform.ID) (*influxdb.StoredStream, error) {
|
||||
st, err := s.s.GetStream(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, _, err := AuthorizeRead(ctx, influxdb.AnnotationsResourceType, id, st.OrgID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return st, nil
|
||||
}
|
||||
|
||||
func (s *AnnotationService) CreateOrUpdateStream(ctx context.Context, orgID platform.ID, stream influxdb.Stream) (*influxdb.ReadStream, error) {
|
||||
// We need to know if the request is creating a new stream, or updating an existing stream to check
|
||||
// permissions appropriately
|
||||
|
||||
// Get the stream by name. An empty slice will be returned if the stream doesn't exist
|
||||
// note: a given org can only have one stream by the same name. this constraint is enforced in the database schema
|
||||
streams, err := s.s.ListStreams(ctx, orgID, influxdb.StreamListFilter{
|
||||
StreamIncludes: []string{stream.Name},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// update an already existing stream
|
||||
if len(streams) == 1 {
|
||||
return s.UpdateStream(ctx, streams[0].ID, stream)
|
||||
}
|
||||
|
||||
// create a new stream if one doesn't already exist
|
||||
if len(streams) == 0 {
|
||||
if _, _, err := AuthorizeCreate(ctx, influxdb.AnnotationsResourceType, orgID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.s.CreateOrUpdateStream(ctx, orgID, stream)
|
||||
}
|
||||
|
||||
// if multiple streams were returned somehow, return an error
|
||||
// this should never happen, so return a server error
|
||||
return nil, &errors.Error{
|
||||
Code: errors.EInternal,
|
||||
Msg: fmt.Sprintf("more than one stream named %q for org %q", streams[0].Name, orgID),
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateStream checks to see if the authorizer on context has write access to the requested stream
|
||||
func (s *AnnotationService) UpdateStream(ctx context.Context, id platform.ID, stream influxdb.Stream) (*influxdb.ReadStream, error) {
|
||||
st, err := s.s.GetStream(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, _, err := AuthorizeWrite(ctx, influxdb.AnnotationsResourceType, id, st.OrgID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.s.UpdateStream(ctx, id, stream)
|
||||
}
|
||||
|
||||
// DeleteStreams checks to see if the authorizer on context has write access to the provided orgID
|
||||
func (s *AnnotationService) DeleteStreams(ctx context.Context, orgID platform.ID, delete influxdb.BasicStream) error {
|
||||
if _, _, err := AuthorizeOrgWriteResource(ctx, influxdb.AnnotationsResourceType, orgID); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.s.DeleteStreams(ctx, orgID, delete)
|
||||
}
|
||||
|
||||
// DeleteStreamByID checks to see if the authorizer on context has write access to the requested stream
|
||||
func (s *AnnotationService) DeleteStreamByID(ctx context.Context, id platform.ID) error {
|
||||
st, err := s.s.GetStream(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, _, err := AuthorizeWrite(ctx, influxdb.AnnotationsResourceType, id, st.OrgID); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.s.DeleteStreamByID(ctx, id)
|
||||
}
|
|
@ -0,0 +1,725 @@
|
|||
package authorizer_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/influxdata/influxdb/v2"
|
||||
"github.com/influxdata/influxdb/v2/authorizer"
|
||||
influxdbcontext "github.com/influxdata/influxdb/v2/context"
|
||||
"github.com/influxdata/influxdb/v2/kit/platform"
|
||||
"github.com/influxdata/influxdb/v2/kit/platform/errors"
|
||||
"github.com/influxdata/influxdb/v2/mock"
|
||||
influxdbtesting "github.com/influxdata/influxdb/v2/testing"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
annOrgID1 = influxdbtesting.IDPtr(1)
|
||||
annOrgID2 = influxdbtesting.IDPtr(10)
|
||||
rID = influxdbtesting.IDPtr(2)
|
||||
)
|
||||
|
||||
func Test_CreateAnnotations(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
wantRet []influxdb.AnnotationEvent
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
"authorized to create annotation(s) with the specified org",
|
||||
[]influxdb.AnnotationEvent{{ID: *rID}},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"not authorized to create annotation(s) with the specified org",
|
||||
nil,
|
||||
&errors.Error{
|
||||
Msg: fmt.Sprintf("write:orgs/%s/annotations is unauthorized", annOrgID1),
|
||||
Code: errors.EUnauthorized,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctrlr := gomock.NewController(t)
|
||||
svc := mock.NewMockAnnotationService(ctrlr)
|
||||
s := authorizer.NewAnnotationService(svc)
|
||||
|
||||
var perm influxdb.Permission
|
||||
if tt.wantErr == nil {
|
||||
perm = newTestAnnotationsPermission(influxdb.WriteAction, annOrgID1)
|
||||
svc.EXPECT().
|
||||
CreateAnnotations(gomock.Any(), *annOrgID1, []influxdb.AnnotationCreate{{}}).
|
||||
Return(tt.wantRet, nil)
|
||||
} else {
|
||||
perm = newTestAnnotationsPermission(influxdb.ReadAction, annOrgID1)
|
||||
}
|
||||
|
||||
ctx := influxdbcontext.SetAuthorizer(context.Background(), mock.NewMockAuthorizer(false, []influxdb.Permission{perm}))
|
||||
got, err := s.CreateAnnotations(ctx, *annOrgID1, []influxdb.AnnotationCreate{{}})
|
||||
require.Equal(t, tt.wantErr, err)
|
||||
require.Equal(t, tt.wantRet, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ListAnnotations(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
wantRet []influxdb.StoredAnnotation
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
"authorized to list annotations for the specified org",
|
||||
[]influxdb.StoredAnnotation{},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"not authorized to list annotations for the specified org",
|
||||
nil,
|
||||
&errors.Error{
|
||||
Msg: fmt.Sprintf("read:orgs/%s/annotations is unauthorized", annOrgID1),
|
||||
Code: errors.EUnauthorized,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctrlr := gomock.NewController(t)
|
||||
svc := mock.NewMockAnnotationService(ctrlr)
|
||||
s := authorizer.NewAnnotationService(svc)
|
||||
|
||||
var perm influxdb.Permission
|
||||
if tt.wantErr == nil {
|
||||
perm = newTestAnnotationsPermission(influxdb.ReadAction, annOrgID1)
|
||||
svc.EXPECT().
|
||||
ListAnnotations(gomock.Any(), *annOrgID1, influxdb.AnnotationListFilter{}).
|
||||
Return(tt.wantRet, nil)
|
||||
}
|
||||
|
||||
ctx := influxdbcontext.SetAuthorizer(context.Background(), mock.NewMockAuthorizer(false, []influxdb.Permission{perm}))
|
||||
got, err := s.ListAnnotations(ctx, *annOrgID1, influxdb.AnnotationListFilter{})
|
||||
require.Equal(t, tt.wantErr, err)
|
||||
require.Equal(t, tt.wantRet, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_GetAnnotation(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
permissionOrg *platform.ID
|
||||
wantRet *influxdb.StoredAnnotation
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
"authorized to access annotation by id",
|
||||
annOrgID1,
|
||||
&influxdb.StoredAnnotation{
|
||||
ID: *rID,
|
||||
OrgID: *annOrgID1,
|
||||
},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"not authorized to access annotation by id",
|
||||
annOrgID2,
|
||||
nil,
|
||||
&errors.Error{
|
||||
Msg: fmt.Sprintf("read:orgs/%s/annotations/%s is unauthorized", annOrgID1, rID),
|
||||
Code: errors.EUnauthorized,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctrlr := gomock.NewController(t)
|
||||
svc := mock.NewMockAnnotationService(ctrlr)
|
||||
s := authorizer.NewAnnotationService(svc)
|
||||
|
||||
svc.EXPECT().
|
||||
GetAnnotation(gomock.Any(), *rID).
|
||||
Return(&influxdb.StoredAnnotation{
|
||||
ID: *rID,
|
||||
OrgID: *annOrgID1,
|
||||
}, nil)
|
||||
|
||||
perm := newTestAnnotationsPermission(influxdb.ReadAction, tt.permissionOrg)
|
||||
|
||||
ctx := context.Background()
|
||||
ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{perm}))
|
||||
got, err := s.GetAnnotation(ctx, *rID)
|
||||
require.Equal(t, tt.wantErr, err)
|
||||
require.Equal(t, tt.wantRet, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_DeleteAnnotations(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
"authorized to delete annotations with the specified org",
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"not authorized to delete annotations with the specified org",
|
||||
&errors.Error{
|
||||
Msg: fmt.Sprintf("write:orgs/%s/annotations is unauthorized", annOrgID1),
|
||||
Code: errors.EUnauthorized,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctrlr := gomock.NewController(t)
|
||||
svc := mock.NewMockAnnotationService(ctrlr)
|
||||
s := authorizer.NewAnnotationService(svc)
|
||||
|
||||
var perm influxdb.Permission
|
||||
if tt.wantErr == nil {
|
||||
perm = newTestAnnotationsPermission(influxdb.WriteAction, annOrgID1)
|
||||
svc.EXPECT().
|
||||
DeleteAnnotations(gomock.Any(), *annOrgID1, influxdb.AnnotationDeleteFilter{}).
|
||||
Return(nil)
|
||||
} else {
|
||||
perm = newTestAnnotationsPermission(influxdb.ReadAction, annOrgID1)
|
||||
}
|
||||
|
||||
ctx := influxdbcontext.SetAuthorizer(context.Background(), mock.NewMockAuthorizer(false, []influxdb.Permission{perm}))
|
||||
err := s.DeleteAnnotations(ctx, *annOrgID1, influxdb.AnnotationDeleteFilter{})
|
||||
require.Equal(t, tt.wantErr, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_DeleteAnnotation(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
permissionOrg *platform.ID
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
"authorized to delete annotation by id",
|
||||
annOrgID1,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"not authorized to delete annotation by id",
|
||||
annOrgID2,
|
||||
&errors.Error{
|
||||
Msg: fmt.Sprintf("write:orgs/%s/annotations/%s is unauthorized", annOrgID1, rID),
|
||||
Code: errors.EUnauthorized,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctrlr := gomock.NewController(t)
|
||||
svc := mock.NewMockAnnotationService(ctrlr)
|
||||
s := authorizer.NewAnnotationService(svc)
|
||||
|
||||
svc.EXPECT().
|
||||
GetAnnotation(gomock.Any(), *rID).
|
||||
Return(&influxdb.StoredAnnotation{
|
||||
ID: *rID,
|
||||
OrgID: *annOrgID1,
|
||||
}, nil)
|
||||
|
||||
perm := newTestAnnotationsPermission(influxdb.WriteAction, tt.permissionOrg)
|
||||
|
||||
if tt.wantErr == nil {
|
||||
svc.EXPECT().
|
||||
DeleteAnnotation(gomock.Any(), *rID).
|
||||
Return(nil)
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{perm}))
|
||||
err := s.DeleteAnnotation(ctx, *rID)
|
||||
require.Equal(t, tt.wantErr, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_UpdateAnnotation(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
permissionOrg *platform.ID
|
||||
wantRet *influxdb.AnnotationEvent
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
"authorized to update annotation by id",
|
||||
annOrgID1,
|
||||
&influxdb.AnnotationEvent{},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"not authorized to update annotation by id",
|
||||
annOrgID2,
|
||||
nil,
|
||||
&errors.Error{
|
||||
Msg: fmt.Sprintf("write:orgs/%s/annotations/%s is unauthorized", annOrgID1, rID),
|
||||
Code: errors.EUnauthorized,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctrlr := gomock.NewController(t)
|
||||
svc := mock.NewMockAnnotationService(ctrlr)
|
||||
s := authorizer.NewAnnotationService(svc)
|
||||
|
||||
svc.EXPECT().
|
||||
GetAnnotation(gomock.Any(), *rID).
|
||||
Return(&influxdb.StoredAnnotation{
|
||||
ID: *rID,
|
||||
OrgID: *annOrgID1,
|
||||
}, nil)
|
||||
|
||||
perm := newTestAnnotationsPermission(influxdb.WriteAction, tt.permissionOrg)
|
||||
|
||||
if tt.wantErr == nil {
|
||||
svc.EXPECT().
|
||||
UpdateAnnotation(gomock.Any(), *rID, influxdb.AnnotationCreate{}).
|
||||
Return(tt.wantRet, nil)
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{perm}))
|
||||
got, err := s.UpdateAnnotation(ctx, *rID, influxdb.AnnotationCreate{})
|
||||
require.Equal(t, tt.wantErr, err)
|
||||
require.Equal(t, tt.wantRet, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ListStreams(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
wantRet []influxdb.StoredStream
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
"authorized to list streams for the specified org",
|
||||
[]influxdb.StoredStream{},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"not authorized to list streams for the specified org",
|
||||
nil,
|
||||
&errors.Error{
|
||||
Msg: fmt.Sprintf("read:orgs/%s/annotations is unauthorized", annOrgID1),
|
||||
Code: errors.EUnauthorized,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctrlr := gomock.NewController(t)
|
||||
svc := mock.NewMockAnnotationService(ctrlr)
|
||||
s := authorizer.NewAnnotationService(svc)
|
||||
|
||||
var perm influxdb.Permission
|
||||
if tt.wantErr == nil {
|
||||
perm = newTestAnnotationsPermission(influxdb.ReadAction, annOrgID1)
|
||||
svc.EXPECT().
|
||||
ListStreams(gomock.Any(), *annOrgID1, influxdb.StreamListFilter{}).
|
||||
Return(tt.wantRet, nil)
|
||||
}
|
||||
|
||||
ctx := influxdbcontext.SetAuthorizer(context.Background(), mock.NewMockAuthorizer(false, []influxdb.Permission{perm}))
|
||||
got, err := s.ListStreams(ctx, *annOrgID1, influxdb.StreamListFilter{})
|
||||
require.Equal(t, tt.wantErr, err)
|
||||
require.Equal(t, tt.wantRet, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_GetStream(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
permissionOrg *platform.ID
|
||||
wantRet *influxdb.StoredStream
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
"authorized to access stream by id",
|
||||
annOrgID1,
|
||||
&influxdb.StoredStream{
|
||||
ID: *rID,
|
||||
OrgID: *annOrgID1,
|
||||
},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"not authorized to access stream by id",
|
||||
annOrgID2,
|
||||
nil,
|
||||
&errors.Error{
|
||||
Msg: fmt.Sprintf("read:orgs/%s/annotations/%s is unauthorized", annOrgID1, rID),
|
||||
Code: errors.EUnauthorized,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctrlr := gomock.NewController(t)
|
||||
svc := mock.NewMockAnnotationService(ctrlr)
|
||||
s := authorizer.NewAnnotationService(svc)
|
||||
|
||||
svc.EXPECT().
|
||||
GetStream(gomock.Any(), *rID).
|
||||
Return(&influxdb.StoredStream{
|
||||
ID: *rID,
|
||||
OrgID: *annOrgID1,
|
||||
}, nil)
|
||||
|
||||
perm := newTestAnnotationsPermission(influxdb.ReadAction, tt.permissionOrg)
|
||||
|
||||
ctx := context.Background()
|
||||
ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{perm}))
|
||||
got, err := s.GetStream(ctx, *rID)
|
||||
require.Equal(t, tt.wantErr, err)
|
||||
require.Equal(t, tt.wantRet, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_CreateOrUpdateStream(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var (
|
||||
testStreamName = "test stream"
|
||||
testStream = influxdb.Stream{
|
||||
Name: testStreamName,
|
||||
}
|
||||
)
|
||||
|
||||
t.Run("updating a stream", func(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
permissionOrg *platform.ID
|
||||
existingStreams []influxdb.StoredStream
|
||||
getStreamRet *influxdb.StoredStream
|
||||
wantRet *influxdb.ReadStream
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
"authorized to update an existing stream",
|
||||
annOrgID1,
|
||||
[]influxdb.StoredStream{{ID: *rID, OrgID: *annOrgID1}},
|
||||
&influxdb.StoredStream{ID: *rID, OrgID: *annOrgID1},
|
||||
&influxdb.ReadStream{ID: *rID},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"not authorized to update an existing stream",
|
||||
annOrgID2,
|
||||
[]influxdb.StoredStream{{ID: *rID, OrgID: *annOrgID1}},
|
||||
&influxdb.StoredStream{ID: *rID, OrgID: *annOrgID1},
|
||||
nil,
|
||||
&errors.Error{
|
||||
Msg: fmt.Sprintf("write:orgs/%s/annotations/%s is unauthorized", annOrgID1, rID),
|
||||
Code: errors.EUnauthorized,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctrlr := gomock.NewController(t)
|
||||
svc := mock.NewMockAnnotationService(ctrlr)
|
||||
s := authorizer.NewAnnotationService(svc)
|
||||
|
||||
svc.EXPECT().
|
||||
ListStreams(gomock.Any(), *tt.permissionOrg, influxdb.StreamListFilter{
|
||||
StreamIncludes: []string{testStreamName},
|
||||
}).
|
||||
Return(tt.existingStreams, nil)
|
||||
|
||||
svc.EXPECT().
|
||||
GetStream(gomock.Any(), tt.existingStreams[0].ID).
|
||||
Return(tt.getStreamRet, nil)
|
||||
|
||||
if tt.wantErr == nil {
|
||||
svc.EXPECT().
|
||||
UpdateStream(gomock.Any(), tt.existingStreams[0].ID, testStream).
|
||||
Return(tt.wantRet, tt.wantErr)
|
||||
}
|
||||
|
||||
perm := newTestAnnotationsPermission(influxdb.WriteAction, tt.permissionOrg)
|
||||
ctx := influxdbcontext.SetAuthorizer(context.Background(), mock.NewMockAuthorizer(false, []influxdb.Permission{perm}))
|
||||
got, err := s.CreateOrUpdateStream(ctx, *tt.permissionOrg, testStream)
|
||||
require.Equal(t, tt.wantErr, err)
|
||||
require.Equal(t, tt.wantRet, got)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("creating a stream", func(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
existingStreams []influxdb.StoredStream
|
||||
wantRet *influxdb.ReadStream
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
"authorized to create a stream with the specified org",
|
||||
[]influxdb.StoredStream{},
|
||||
&influxdb.ReadStream{},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"not authorized to create a stream with the specified org",
|
||||
[]influxdb.StoredStream{},
|
||||
nil,
|
||||
&errors.Error{
|
||||
Msg: fmt.Sprintf("write:orgs/%s/annotations is unauthorized", annOrgID1),
|
||||
Code: errors.EUnauthorized,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctrlr := gomock.NewController(t)
|
||||
svc := mock.NewMockAnnotationService(ctrlr)
|
||||
s := authorizer.NewAnnotationService(svc)
|
||||
|
||||
svc.EXPECT().
|
||||
ListStreams(gomock.Any(), *annOrgID1, influxdb.StreamListFilter{
|
||||
StreamIncludes: []string{testStreamName},
|
||||
}).
|
||||
Return(tt.existingStreams, nil)
|
||||
|
||||
var perm influxdb.Permission
|
||||
if tt.wantErr == nil {
|
||||
perm = newTestAnnotationsPermission(influxdb.WriteAction, annOrgID1)
|
||||
svc.EXPECT().
|
||||
CreateOrUpdateStream(gomock.Any(), *annOrgID1, testStream).
|
||||
Return(tt.wantRet, nil)
|
||||
} else {
|
||||
perm = newTestAnnotationsPermission(influxdb.ReadAction, annOrgID1)
|
||||
}
|
||||
|
||||
ctx := influxdbcontext.SetAuthorizer(context.Background(), mock.NewMockAuthorizer(false, []influxdb.Permission{perm}))
|
||||
got, err := s.CreateOrUpdateStream(ctx, *annOrgID1, testStream)
|
||||
require.Equal(t, tt.wantErr, err)
|
||||
require.Equal(t, tt.wantRet, got)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("stream list longer than 1 returns a server error", func(t *testing.T) {
|
||||
ctrlr := gomock.NewController(t)
|
||||
svc := mock.NewMockAnnotationService(ctrlr)
|
||||
s := authorizer.NewAnnotationService(svc)
|
||||
|
||||
svc.EXPECT().
|
||||
ListStreams(gomock.Any(), *annOrgID1, influxdb.StreamListFilter{
|
||||
StreamIncludes: []string{testStreamName},
|
||||
}).
|
||||
Return([]influxdb.StoredStream{{Name: testStreamName}, {Name: testStreamName}}, nil)
|
||||
|
||||
wantErr := &errors.Error{
|
||||
Code: errors.EInternal,
|
||||
Msg: fmt.Sprintf("more than one stream named %q for org %q", testStreamName, annOrgID1),
|
||||
}
|
||||
|
||||
got, err := s.CreateOrUpdateStream(context.Background(), *annOrgID1, testStream)
|
||||
require.Nil(t, got)
|
||||
require.Equal(t, err, wantErr)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_UpdateStream(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
permissionOrg *platform.ID
|
||||
wantRet *influxdb.ReadStream
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
"authorized to update stream by id",
|
||||
annOrgID1,
|
||||
&influxdb.ReadStream{},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"not authorized to update stream by id",
|
||||
annOrgID2,
|
||||
nil,
|
||||
&errors.Error{
|
||||
Msg: fmt.Sprintf("write:orgs/%s/annotations/%s is unauthorized", annOrgID1, rID),
|
||||
Code: errors.EUnauthorized,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctrlr := gomock.NewController(t)
|
||||
svc := mock.NewMockAnnotationService(ctrlr)
|
||||
s := authorizer.NewAnnotationService(svc)
|
||||
|
||||
svc.EXPECT().
|
||||
GetStream(gomock.Any(), *rID).
|
||||
Return(&influxdb.StoredStream{
|
||||
ID: *rID,
|
||||
OrgID: *annOrgID1,
|
||||
}, nil)
|
||||
|
||||
perm := newTestAnnotationsPermission(influxdb.WriteAction, tt.permissionOrg)
|
||||
|
||||
if tt.wantErr == nil {
|
||||
svc.EXPECT().
|
||||
UpdateStream(gomock.Any(), *rID, influxdb.Stream{}).
|
||||
Return(tt.wantRet, nil)
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{perm}))
|
||||
got, err := s.UpdateStream(ctx, *rID, influxdb.Stream{})
|
||||
require.Equal(t, tt.wantErr, err)
|
||||
require.Equal(t, tt.wantRet, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_DeleteStreams(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
"authorized to delete streams with the specified org",
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"not authorized to delete streams with the specified org",
|
||||
&errors.Error{
|
||||
Msg: fmt.Sprintf("write:orgs/%s/annotations is unauthorized", annOrgID1),
|
||||
Code: errors.EUnauthorized,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctrlr := gomock.NewController(t)
|
||||
svc := mock.NewMockAnnotationService(ctrlr)
|
||||
s := authorizer.NewAnnotationService(svc)
|
||||
|
||||
var perm influxdb.Permission
|
||||
if tt.wantErr == nil {
|
||||
perm = newTestAnnotationsPermission(influxdb.WriteAction, annOrgID1)
|
||||
svc.EXPECT().
|
||||
DeleteStreams(gomock.Any(), *annOrgID1, influxdb.BasicStream{}).
|
||||
Return(nil)
|
||||
} else {
|
||||
perm = newTestAnnotationsPermission(influxdb.ReadAction, annOrgID1)
|
||||
}
|
||||
|
||||
ctx := influxdbcontext.SetAuthorizer(context.Background(), mock.NewMockAuthorizer(false, []influxdb.Permission{perm}))
|
||||
err := s.DeleteStreams(ctx, *annOrgID1, influxdb.BasicStream{})
|
||||
require.Equal(t, tt.wantErr, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_DeleteStreamByID(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
permissionOrg *platform.ID
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
"authorized to delete stream by id",
|
||||
annOrgID1,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"not authorized to delete stream by id",
|
||||
annOrgID2,
|
||||
&errors.Error{
|
||||
Msg: fmt.Sprintf("write:orgs/%s/annotations/%s is unauthorized", annOrgID1, rID),
|
||||
Code: errors.EUnauthorized,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctrlr := gomock.NewController(t)
|
||||
svc := mock.NewMockAnnotationService(ctrlr)
|
||||
s := authorizer.NewAnnotationService(svc)
|
||||
|
||||
svc.EXPECT().
|
||||
GetStream(gomock.Any(), *rID).
|
||||
Return(&influxdb.StoredStream{
|
||||
ID: *rID,
|
||||
OrgID: *annOrgID1,
|
||||
}, nil)
|
||||
|
||||
perm := newTestAnnotationsPermission(influxdb.WriteAction, tt.permissionOrg)
|
||||
|
||||
if tt.wantErr == nil {
|
||||
svc.EXPECT().
|
||||
DeleteStreamByID(gomock.Any(), *rID).
|
||||
Return(nil)
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{perm}))
|
||||
err := s.DeleteStreamByID(ctx, *rID)
|
||||
require.Equal(t, tt.wantErr, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func newTestAnnotationsPermission(action influxdb.Action, orgID *platform.ID) influxdb.Permission {
|
||||
return influxdb.Permission{
|
||||
Action: action,
|
||||
Resource: influxdb.Resource{
|
||||
Type: influxdb.AnnotationsResourceType,
|
||||
OrgID: orgID,
|
||||
},
|
||||
}
|
||||
}
|
|
@ -92,6 +92,42 @@ func AuthorizeFindDashboards(ctx context.Context, rs []*influxdb.Dashboard) ([]*
|
|||
return rrs, len(rrs), nil
|
||||
}
|
||||
|
||||
// AuthorizeFindAnnotations takes the given items and returns only the ones that the user is authorized to read.
|
||||
func AuthorizeFindAnnotations(ctx context.Context, rs []influxdb.StoredAnnotation) ([]influxdb.StoredAnnotation, int, error) {
|
||||
// This filters without allocating
|
||||
// https://github.com/golang/go/wiki/SliceTricks#filtering-without-allocating
|
||||
rrs := rs[:0]
|
||||
for _, r := range rs {
|
||||
_, _, err := AuthorizeRead(ctx, influxdb.AnnotationsResourceType, r.ID, r.OrgID)
|
||||
if err != nil && errors.ErrorCode(err) != errors.EUnauthorized {
|
||||
return nil, 0, err
|
||||
}
|
||||
if errors.ErrorCode(err) == errors.EUnauthorized {
|
||||
continue
|
||||
}
|
||||
rrs = append(rrs, r)
|
||||
}
|
||||
return rrs, len(rrs), nil
|
||||
}
|
||||
|
||||
// AuthorizeFindStreams takes the given items and returns only the ones that the user is authorized to read.
|
||||
func AuthorizeFindStreams(ctx context.Context, rs []influxdb.StoredStream) ([]influxdb.StoredStream, int, error) {
|
||||
// This filters without allocating
|
||||
// https://github.com/golang/go/wiki/SliceTricks#filtering-without-allocating
|
||||
rrs := rs[:0]
|
||||
for _, r := range rs {
|
||||
_, _, err := AuthorizeRead(ctx, influxdb.AnnotationsResourceType, r.ID, r.OrgID)
|
||||
if err != nil && errors.ErrorCode(err) != errors.EUnauthorized {
|
||||
return nil, 0, err
|
||||
}
|
||||
if errors.ErrorCode(err) == errors.EUnauthorized {
|
||||
continue
|
||||
}
|
||||
rrs = append(rrs, r)
|
||||
}
|
||||
return rrs, len(rrs), nil
|
||||
}
|
||||
|
||||
// AuthorizeFindOrganizations takes the given items and returns only the ones that the user is authorized to read.
|
||||
func AuthorizeFindOrganizations(ctx context.Context, rs []*influxdb.Organization) ([]*influxdb.Organization, int, error) {
|
||||
// This filters without allocating
|
||||
|
|
|
@ -61,7 +61,7 @@ func Test_GetNotebook(t *testing.T) {
|
|||
GetNotebook(gomock.Any(), *nbID).
|
||||
Return(newTestNotebook(*orgID1), nil)
|
||||
|
||||
perm := newTestPermission(influxdb.ReadAction, tt.permissionOrg)
|
||||
perm := newTestNotebooksPermission(influxdb.ReadAction, tt.permissionOrg)
|
||||
|
||||
ctx := context.Background()
|
||||
ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{perm}))
|
||||
|
@ -107,7 +107,7 @@ func Test_CreateNotebook(t *testing.T) {
|
|||
svc := mock.NewMockNotebookService(ctrlr)
|
||||
s := authorizer.NewNotebookService(svc)
|
||||
|
||||
perm := newTestPermission(influxdb.WriteAction, tt.permissionOrg)
|
||||
perm := newTestNotebooksPermission(influxdb.WriteAction, tt.permissionOrg)
|
||||
nb := newTestReqBody(*tt.notebookOrg)
|
||||
|
||||
if tt.wantErr == nil {
|
||||
|
@ -163,7 +163,7 @@ func Test_UpdateNotebook(t *testing.T) {
|
|||
GetNotebook(gomock.Any(), *nbID).
|
||||
Return(newTestNotebook(*tt.notebookOrg), nil)
|
||||
|
||||
perm := newTestPermission(influxdb.WriteAction, tt.permissionOrg)
|
||||
perm := newTestNotebooksPermission(influxdb.WriteAction, tt.permissionOrg)
|
||||
nb := newTestReqBody(*tt.notebookOrg)
|
||||
|
||||
if tt.wantErr == nil {
|
||||
|
@ -216,7 +216,7 @@ func Test_DeleteNotebook(t *testing.T) {
|
|||
GetNotebook(gomock.Any(), *nbID).
|
||||
Return(newTestNotebook(*tt.notebookOrg), nil)
|
||||
|
||||
perm := newTestPermission(influxdb.WriteAction, tt.permissionOrg)
|
||||
perm := newTestNotebooksPermission(influxdb.WriteAction, tt.permissionOrg)
|
||||
|
||||
if tt.wantErr == nil {
|
||||
svc.EXPECT().
|
||||
|
@ -266,7 +266,7 @@ func Test_ListNotebooks(t *testing.T) {
|
|||
svc := mock.NewMockNotebookService(ctrlr)
|
||||
s := authorizer.NewNotebookService(svc)
|
||||
|
||||
perm := newTestPermission(influxdb.ReadAction, tt.permissionOrg)
|
||||
perm := newTestNotebooksPermission(influxdb.ReadAction, tt.permissionOrg)
|
||||
filter := influxdb.NotebookListFilter{OrgID: *tt.notebookOrg}
|
||||
|
||||
if tt.wantErr == nil {
|
||||
|
@ -304,7 +304,7 @@ func newTestReqBody(orgID platform.ID) *influxdb.NotebookReqBody {
|
|||
}
|
||||
}
|
||||
|
||||
func newTestPermission(action influxdb.Action, orgID *platform.ID) influxdb.Permission {
|
||||
func newTestNotebooksPermission(action influxdb.Action, orgID *platform.ID) influxdb.Permission {
|
||||
return influxdb.Permission{
|
||||
Action: action,
|
||||
Resource: influxdb.Resource{
|
||||
|
|
5
authz.go
5
authz.go
|
@ -137,6 +137,8 @@ const (
|
|||
DBRPResourceType = ResourceType("dbrp") // 17
|
||||
// NotebooksResourceType gives permission to one or more notebooks.
|
||||
NotebooksResourceType = ResourceType("notebooks") // 18
|
||||
// AnnotationsResourceType gives permission to one or more annotations.
|
||||
AnnotationsResourceType = ResourceType("annotations") // 19
|
||||
)
|
||||
|
||||
// AllResourceTypes is the list of all known resource types.
|
||||
|
@ -160,6 +162,7 @@ var AllResourceTypes = []ResourceType{
|
|||
ChecksResourceType, // 16
|
||||
DBRPResourceType, // 17
|
||||
NotebooksResourceType, // 18
|
||||
AnnotationsResourceType, // 19
|
||||
// NOTE: when modifying this list, please update the swagger for components.schemas.Permission resource enum.
|
||||
}
|
||||
|
||||
|
@ -179,6 +182,7 @@ var OrgResourceTypes = []ResourceType{
|
|||
ChecksResourceType, // 16
|
||||
DBRPResourceType, // 17
|
||||
NotebooksResourceType, // 18
|
||||
AnnotationsResourceType, // 19
|
||||
}
|
||||
|
||||
// Valid checks if the resource type is a member of the ResourceType enum.
|
||||
|
@ -208,6 +212,7 @@ func (t ResourceType) Valid() (err error) {
|
|||
case ChecksResourceType: // 16
|
||||
case DBRPResourceType: // 17
|
||||
case NotebooksResourceType: // 18
|
||||
case AnnotationsResourceType: // 19
|
||||
default:
|
||||
err = ErrInvalidResourceType
|
||||
}
|
||||
|
|
|
@ -325,7 +325,8 @@ func TestPermissionAllResources_Valid(t *testing.T) {
|
|||
platform.BucketsResourceType,
|
||||
platform.DashboardsResourceType,
|
||||
platform.SourcesResourceType,
|
||||
platform.DashboardsResourceType,
|
||||
platform.NotebooksResourceType,
|
||||
platform.AnnotationsResourceType,
|
||||
}
|
||||
|
||||
for _, rt := range resources {
|
||||
|
|
|
@ -6,37 +6,36 @@ package mock
|
|||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
influxdb "github.com/influxdata/influxdb/v2"
|
||||
platform "github.com/influxdata/influxdb/v2/kit/platform"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
// MockAnnotationService is a mock of AnnotationService interface.
|
||||
// MockAnnotationService is a mock of AnnotationService interface
|
||||
type MockAnnotationService struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockAnnotationServiceMockRecorder
|
||||
}
|
||||
|
||||
// MockAnnotationServiceMockRecorder is the mock recorder for MockAnnotationService.
|
||||
// MockAnnotationServiceMockRecorder is the mock recorder for MockAnnotationService
|
||||
type MockAnnotationServiceMockRecorder struct {
|
||||
mock *MockAnnotationService
|
||||
}
|
||||
|
||||
// NewMockAnnotationService creates a new mock instance.
|
||||
// NewMockAnnotationService creates a new mock instance
|
||||
func NewMockAnnotationService(ctrl *gomock.Controller) *MockAnnotationService {
|
||||
mock := &MockAnnotationService{ctrl: ctrl}
|
||||
mock.recorder = &MockAnnotationServiceMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
func (m *MockAnnotationService) EXPECT() *MockAnnotationServiceMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// CreateAnnotations mocks base method.
|
||||
// CreateAnnotations mocks base method
|
||||
func (m *MockAnnotationService) CreateAnnotations(ctx context.Context, orgID platform.ID, create []influxdb.AnnotationCreate) ([]influxdb.AnnotationEvent, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateAnnotations", ctx, orgID, create)
|
||||
|
@ -45,42 +44,43 @@ func (m *MockAnnotationService) CreateAnnotations(ctx context.Context, orgID pla
|
|||
return ret0, ret1
|
||||
}
|
||||
|
||||
// CreateAnnotations indicates an expected call of CreateAnnotations.
|
||||
// CreateAnnotations indicates an expected call of CreateAnnotations
|
||||
func (mr *MockAnnotationServiceMockRecorder) CreateAnnotations(ctx, orgID, create interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAnnotations", reflect.TypeOf((*MockAnnotationService)(nil).CreateAnnotations), ctx, orgID, create)
|
||||
}
|
||||
|
||||
// CreateOrUpdateStream mocks base method.
|
||||
func (m *MockAnnotationService) CreateOrUpdateStream(ctx context.Context, stream influxdb.Stream) (*influxdb.ReadStream, error) {
|
||||
// ListAnnotations mocks base method
|
||||
func (m *MockAnnotationService) ListAnnotations(ctx context.Context, orgID platform.ID, filter influxdb.AnnotationListFilter) ([]influxdb.StoredAnnotation, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateOrUpdateStream", ctx, stream)
|
||||
ret0, _ := ret[0].(*influxdb.ReadStream)
|
||||
ret := m.ctrl.Call(m, "ListAnnotations", ctx, orgID, filter)
|
||||
ret0, _ := ret[0].([]influxdb.StoredAnnotation)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// CreateOrUpdateStream indicates an expected call of CreateOrUpdateStream.
|
||||
func (mr *MockAnnotationServiceMockRecorder) CreateOrUpdateStream(ctx, stream interface{}) *gomock.Call {
|
||||
// ListAnnotations indicates an expected call of ListAnnotations
|
||||
func (mr *MockAnnotationServiceMockRecorder) ListAnnotations(ctx, orgID, filter interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateOrUpdateStream", reflect.TypeOf((*MockAnnotationService)(nil).CreateOrUpdateStream), ctx, stream)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAnnotations", reflect.TypeOf((*MockAnnotationService)(nil).ListAnnotations), ctx, orgID, filter)
|
||||
}
|
||||
|
||||
// DeleteAnnotation mocks base method.
|
||||
func (m *MockAnnotationService) DeleteAnnotation(ctx context.Context, id platform.ID) error {
|
||||
// GetAnnotation mocks base method
|
||||
func (m *MockAnnotationService) GetAnnotation(ctx context.Context, id platform.ID) (*influxdb.StoredAnnotation, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DeleteAnnotation", ctx, id)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
ret := m.ctrl.Call(m, "GetAnnotation", ctx, id)
|
||||
ret0, _ := ret[0].(*influxdb.StoredAnnotation)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// DeleteAnnotation indicates an expected call of DeleteAnnotation.
|
||||
func (mr *MockAnnotationServiceMockRecorder) DeleteAnnotation(ctx, id interface{}) *gomock.Call {
|
||||
// GetAnnotation indicates an expected call of GetAnnotation
|
||||
func (mr *MockAnnotationServiceMockRecorder) GetAnnotation(ctx, id interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAnnotation", reflect.TypeOf((*MockAnnotationService)(nil).DeleteAnnotation), ctx, id)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAnnotation", reflect.TypeOf((*MockAnnotationService)(nil).GetAnnotation), ctx, id)
|
||||
}
|
||||
|
||||
// DeleteAnnotations mocks base method.
|
||||
// DeleteAnnotations mocks base method
|
||||
func (m *MockAnnotationService) DeleteAnnotations(ctx context.Context, orgID platform.ID, delete influxdb.AnnotationDeleteFilter) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DeleteAnnotations", ctx, orgID, delete)
|
||||
|
@ -88,86 +88,27 @@ func (m *MockAnnotationService) DeleteAnnotations(ctx context.Context, orgID pla
|
|||
return ret0
|
||||
}
|
||||
|
||||
// DeleteAnnotations indicates an expected call of DeleteAnnotations.
|
||||
// DeleteAnnotations indicates an expected call of DeleteAnnotations
|
||||
func (mr *MockAnnotationServiceMockRecorder) DeleteAnnotations(ctx, orgID, delete interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAnnotations", reflect.TypeOf((*MockAnnotationService)(nil).DeleteAnnotations), ctx, orgID, delete)
|
||||
}
|
||||
|
||||
// DeleteStreamByID mocks base method.
|
||||
func (m *MockAnnotationService) DeleteStreamByID(ctx context.Context, id platform.ID) error {
|
||||
// DeleteAnnotation mocks base method
|
||||
func (m *MockAnnotationService) DeleteAnnotation(ctx context.Context, id platform.ID) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DeleteStreamByID", ctx, id)
|
||||
ret := m.ctrl.Call(m, "DeleteAnnotation", ctx, id)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// DeleteStreamByID indicates an expected call of DeleteStreamByID.
|
||||
func (mr *MockAnnotationServiceMockRecorder) DeleteStreamByID(ctx, id interface{}) *gomock.Call {
|
||||
// DeleteAnnotation indicates an expected call of DeleteAnnotation
|
||||
func (mr *MockAnnotationServiceMockRecorder) DeleteAnnotation(ctx, id interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteStreamByID", reflect.TypeOf((*MockAnnotationService)(nil).DeleteStreamByID), ctx, id)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAnnotation", reflect.TypeOf((*MockAnnotationService)(nil).DeleteAnnotation), ctx, id)
|
||||
}
|
||||
|
||||
// DeleteStreams mocks base method.
|
||||
func (m *MockAnnotationService) DeleteStreams(ctx context.Context, delete influxdb.BasicStream) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DeleteStreams", ctx, delete)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// DeleteStreams indicates an expected call of DeleteStreams.
|
||||
func (mr *MockAnnotationServiceMockRecorder) DeleteStreams(ctx, delete interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteStreams", reflect.TypeOf((*MockAnnotationService)(nil).DeleteStreams), ctx, delete)
|
||||
}
|
||||
|
||||
// GetAnnotation mocks base method.
|
||||
func (m *MockAnnotationService) GetAnnotation(ctx context.Context, id platform.ID) (*influxdb.AnnotationEvent, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetAnnotation", ctx, id)
|
||||
ret0, _ := ret[0].(*influxdb.AnnotationEvent)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetAnnotation indicates an expected call of GetAnnotation.
|
||||
func (mr *MockAnnotationServiceMockRecorder) GetAnnotation(ctx, id interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAnnotation", reflect.TypeOf((*MockAnnotationService)(nil).GetAnnotation), ctx, id)
|
||||
}
|
||||
|
||||
// ListAnnotations mocks base method.
|
||||
func (m *MockAnnotationService) ListAnnotations(ctx context.Context, orgID platform.ID, filter influxdb.AnnotationListFilter) (influxdb.ReadAnnotations, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ListAnnotations", ctx, orgID, filter)
|
||||
ret0, _ := ret[0].(influxdb.ReadAnnotations)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ListAnnotations indicates an expected call of ListAnnotations.
|
||||
func (mr *MockAnnotationServiceMockRecorder) ListAnnotations(ctx, orgID, filter interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAnnotations", reflect.TypeOf((*MockAnnotationService)(nil).ListAnnotations), ctx, orgID, filter)
|
||||
}
|
||||
|
||||
// ListStreams mocks base method.
|
||||
func (m *MockAnnotationService) ListStreams(ctx context.Context, orgID platform.ID, filter influxdb.StreamListFilter) ([]influxdb.ReadStream, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ListStreams", ctx, orgID, filter)
|
||||
ret0, _ := ret[0].([]influxdb.ReadStream)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ListStreams indicates an expected call of ListStreams.
|
||||
func (mr *MockAnnotationServiceMockRecorder) ListStreams(ctx, orgID, filter interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListStreams", reflect.TypeOf((*MockAnnotationService)(nil).ListStreams), ctx, orgID, filter)
|
||||
}
|
||||
|
||||
// UpdateAnnotation mocks base method.
|
||||
// UpdateAnnotation mocks base method
|
||||
func (m *MockAnnotationService) UpdateAnnotation(ctx context.Context, id platform.ID, update influxdb.AnnotationCreate) (*influxdb.AnnotationEvent, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UpdateAnnotation", ctx, id, update)
|
||||
|
@ -176,13 +117,58 @@ func (m *MockAnnotationService) UpdateAnnotation(ctx context.Context, id platfor
|
|||
return ret0, ret1
|
||||
}
|
||||
|
||||
// UpdateAnnotation indicates an expected call of UpdateAnnotation.
|
||||
// UpdateAnnotation indicates an expected call of UpdateAnnotation
|
||||
func (mr *MockAnnotationServiceMockRecorder) UpdateAnnotation(ctx, id, update interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateAnnotation", reflect.TypeOf((*MockAnnotationService)(nil).UpdateAnnotation), ctx, id, update)
|
||||
}
|
||||
|
||||
// UpdateStream mocks base method.
|
||||
// ListStreams mocks base method
|
||||
func (m *MockAnnotationService) ListStreams(ctx context.Context, orgID platform.ID, filter influxdb.StreamListFilter) ([]influxdb.StoredStream, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ListStreams", ctx, orgID, filter)
|
||||
ret0, _ := ret[0].([]influxdb.StoredStream)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ListStreams indicates an expected call of ListStreams
|
||||
func (mr *MockAnnotationServiceMockRecorder) ListStreams(ctx, orgID, filter interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListStreams", reflect.TypeOf((*MockAnnotationService)(nil).ListStreams), ctx, orgID, filter)
|
||||
}
|
||||
|
||||
// CreateOrUpdateStream mocks base method
|
||||
func (m *MockAnnotationService) CreateOrUpdateStream(ctx context.Context, orgID platform.ID, stream influxdb.Stream) (*influxdb.ReadStream, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateOrUpdateStream", ctx, orgID, stream)
|
||||
ret0, _ := ret[0].(*influxdb.ReadStream)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// CreateOrUpdateStream indicates an expected call of CreateOrUpdateStream
|
||||
func (mr *MockAnnotationServiceMockRecorder) CreateOrUpdateStream(ctx, orgID, stream interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateOrUpdateStream", reflect.TypeOf((*MockAnnotationService)(nil).CreateOrUpdateStream), ctx, orgID, stream)
|
||||
}
|
||||
|
||||
// GetStream mocks base method
|
||||
func (m *MockAnnotationService) GetStream(ctx context.Context, id platform.ID) (*influxdb.StoredStream, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetStream", ctx, id)
|
||||
ret0, _ := ret[0].(*influxdb.StoredStream)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetStream indicates an expected call of GetStream
|
||||
func (mr *MockAnnotationServiceMockRecorder) GetStream(ctx, id interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStream", reflect.TypeOf((*MockAnnotationService)(nil).GetStream), ctx, id)
|
||||
}
|
||||
|
||||
// UpdateStream mocks base method
|
||||
func (m *MockAnnotationService) UpdateStream(ctx context.Context, id platform.ID, stream influxdb.Stream) (*influxdb.ReadStream, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UpdateStream", ctx, id, stream)
|
||||
|
@ -191,8 +177,36 @@ func (m *MockAnnotationService) UpdateStream(ctx context.Context, id platform.ID
|
|||
return ret0, ret1
|
||||
}
|
||||
|
||||
// UpdateStream indicates an expected call of UpdateStream.
|
||||
// UpdateStream indicates an expected call of UpdateStream
|
||||
func (mr *MockAnnotationServiceMockRecorder) UpdateStream(ctx, id, stream interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateStream", reflect.TypeOf((*MockAnnotationService)(nil).UpdateStream), ctx, id, stream)
|
||||
}
|
||||
|
||||
// DeleteStreams mocks base method
|
||||
func (m *MockAnnotationService) DeleteStreams(ctx context.Context, orgID platform.ID, delete influxdb.BasicStream) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DeleteStreams", ctx, orgID, delete)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// DeleteStreams indicates an expected call of DeleteStreams
|
||||
func (mr *MockAnnotationServiceMockRecorder) DeleteStreams(ctx, orgID, delete interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteStreams", reflect.TypeOf((*MockAnnotationService)(nil).DeleteStreams), ctx, orgID, delete)
|
||||
}
|
||||
|
||||
// DeleteStreamByID mocks base method
|
||||
func (m *MockAnnotationService) DeleteStreamByID(ctx context.Context, id platform.ID) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DeleteStreamByID", ctx, id)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// DeleteStreamByID indicates an expected call of DeleteStreamByID
|
||||
func (mr *MockAnnotationServiceMockRecorder) DeleteStreamByID(ctx, id interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteStreamByID", reflect.TypeOf((*MockAnnotationService)(nil).DeleteStreamByID), ctx, id)
|
||||
}
|
||||
|
|
|
@ -162,6 +162,8 @@ func TestOnboardAuth(t *testing.T) {
|
|||
{Action: influxdb.WriteAction, Resource: influxdb.Resource{OrgID: &onboard.Org.ID, Type: influxdb.DBRPResourceType}},
|
||||
{Action: influxdb.ReadAction, Resource: influxdb.Resource{OrgID: &onboard.Org.ID, Type: influxdb.NotebooksResourceType}},
|
||||
{Action: influxdb.WriteAction, Resource: influxdb.Resource{OrgID: &onboard.Org.ID, Type: influxdb.NotebooksResourceType}},
|
||||
{Action: influxdb.ReadAction, Resource: influxdb.Resource{OrgID: &onboard.Org.ID, Type: influxdb.AnnotationsResourceType}},
|
||||
{Action: influxdb.WriteAction, Resource: influxdb.Resource{OrgID: &onboard.Org.ID, Type: influxdb.AnnotationsResourceType}},
|
||||
{Action: influxdb.ReadAction, Resource: influxdb.Resource{ID: &onboard.User.ID, Type: influxdb.UsersResourceType}},
|
||||
{Action: influxdb.WriteAction, Resource: influxdb.Resource{ID: &onboard.User.ID, Type: influxdb.UsersResourceType}},
|
||||
}
|
||||
|
|
|
@ -157,6 +157,7 @@ func TestFindPermissionsFromUser(t *testing.T) {
|
|||
influxdb.Permission{Action: influxdb.ReadAction, Resource: influxdb.Resource{OrgID: &orgID, Type: influxdb.ChecksResourceType}},
|
||||
influxdb.Permission{Action: influxdb.ReadAction, Resource: influxdb.Resource{OrgID: &orgID, Type: influxdb.DBRPResourceType}},
|
||||
influxdb.Permission{Action: influxdb.ReadAction, Resource: influxdb.Resource{OrgID: &orgID, Type: influxdb.NotebooksResourceType}},
|
||||
influxdb.Permission{Action: influxdb.ReadAction, Resource: influxdb.Resource{OrgID: &orgID, Type: influxdb.AnnotationsResourceType}},
|
||||
influxdb.Permission{Action: influxdb.ReadAction, Resource: influxdb.Resource{Type: influxdb.UsersResourceType, ID: &u.ID}},
|
||||
influxdb.Permission{Action: influxdb.WriteAction, Resource: influxdb.Resource{Type: influxdb.UsersResourceType, ID: &u.ID}},
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue