From 8975fd2365a6a1d5ff8fc5c599153ba442c8a669 Mon Sep 17 00:00:00 2001 From: Alirie Gray Date: Tue, 7 Apr 2020 11:13:27 -0700 Subject: [PATCH] refactor(tenant): move bucket and urm auth layers to tenant service (#17474) Co-authored-by: Lyon Hill --- authorizer/agent_test.go | 5 +- authorizer/auth_test.go | 6 +- authorizer/bucket_test.go | 12 +- authorizer/check_test.go | 12 +- authorizer/dashboard_test.go | 14 +- authorizer/label_test.go | 16 +- authorizer/notification_endpoint_test.go | 12 +- authorizer/notification_rule_test.go | 12 +- authorizer/org_test.go | 13 +- authorizer/password_test.go | 8 +- authorizer/scraper_test.go | 10 +- authorizer/secret_test.go | 12 +- authorizer/source_test.go | 12 +- authorizer/telegraf_test.go | 10 +- authorizer/urm_test.go | 4 +- authorizer/user_test.go | 12 +- authorizer/util_test.go | 24 - authorizer/variable_test.go | 12 +- cmd/influxd/launcher/launcher.go | 14 +- cmd/influxd/launcher/launcher_helpers.go | 3 +- http/document_service_test.go | 2 +- http/platform_handler.go | 5 +- mock/authorization.go | 57 +- query/stdlib/testing/end_to_end_test.go | 2 +- tenant/error.go | 5 + tenant/http_server.go | 41 ++ tenant/http_server_bucket.go | 15 +- tenant/http_server_org.go | 23 +- tenant/middleware_bucket_auth.go | 122 +++++ tenant/middleware_bucket_auth_test.go | 628 ++++++++++++++++++++++ tenant/middleware_org_auth_test.go | 557 +++++++++++++++++++ tenant/middleware_urm_auth.go | 90 ++++ tenant/middleware_urm_auth_test.go | 334 ++++++++++++ tenant/middleware_user_auth.go | 34 +- tenant/middleware_user_auth_test.go | 648 +++++++++++++++++++++++ tenant/service_user.go | 4 +- testing/tenant.go | 1 + 37 files changed, 2627 insertions(+), 164 deletions(-) delete mode 100644 authorizer/util_test.go create mode 100644 tenant/middleware_bucket_auth.go create mode 100644 tenant/middleware_bucket_auth_test.go create mode 100644 tenant/middleware_org_auth_test.go create mode 100644 tenant/middleware_urm_auth.go create mode 100644 tenant/middleware_urm_auth_test.go create mode 100644 tenant/middleware_user_auth_test.go diff --git a/authorizer/agent_test.go b/authorizer/agent_test.go index 0a2349ea76..0859260d5f 100644 --- a/authorizer/agent_test.go +++ b/authorizer/agent_test.go @@ -7,6 +7,7 @@ import ( "github.com/influxdata/influxdb/v2" "github.com/influxdata/influxdb/v2/authorizer" icontext "github.com/influxdata/influxdb/v2/context" + "github.com/influxdata/influxdb/v2/mock" influxdbtesting "github.com/influxdata/influxdb/v2/testing" "github.com/stretchr/testify/require" ) @@ -154,7 +155,7 @@ func Test_Agent(t *testing.T) { for _, tt := range tests { fn := func(t *testing.T) { - ctx := icontext.SetAuthorizer(context.TODO(), &Authorizer{tt.permissions}) + ctx := icontext.SetAuthorizer(context.TODO(), mock.NewMockAuthorizer(false, tt.permissions)) agent := new(authorizer.AuthAgent) @@ -279,7 +280,7 @@ func Test_Agent(t *testing.T) { for _, tt := range tests { fn := func(t *testing.T) { - ctx := icontext.SetAuthorizer(context.TODO(), &Authorizer{tt.permissions}) + ctx := icontext.SetAuthorizer(context.TODO(), mock.NewMockAuthorizer(false, tt.permissions)) agent := new(authorizer.AuthAgent) diff --git a/authorizer/auth_test.go b/authorizer/auth_test.go index 4825c53ddd..c75c37c93d 100644 --- a/authorizer/auth_test.go +++ b/authorizer/auth_test.go @@ -159,7 +159,7 @@ func TestAuthorizationService_ReadAuthorization(t *testing.T) { s := authorizer.NewAuthorizationService(m) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) t.Run("find authorization by id", func(t *testing.T) { _, err := s.FindAuthorizationByID(ctx, 10) @@ -298,7 +298,7 @@ func TestAuthorizationService_WriteAuthorization(t *testing.T) { s := authorizer.NewAuthorizationService(m) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) t.Run("update authorization", func(t *testing.T) { _, err := s.UpdateAuthorization(ctx, 10, &influxdb.AuthorizationUpdate{Status: influxdb.Active.Ptr()}) @@ -429,7 +429,7 @@ func TestAuthorizationService_CreateAuthorization(t *testing.T) { s := authorizer.NewAuthorizationService(m) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) err := s.CreateAuthorization(ctx, &influxdb.Authorization{OrgID: 1, UserID: 1}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) diff --git a/authorizer/bucket_test.go b/authorizer/bucket_test.go index d8cd3eb1ef..dfd0ebe5f8 100644 --- a/authorizer/bucket_test.go +++ b/authorizer/bucket_test.go @@ -107,7 +107,7 @@ func TestBucketService_FindBucketByID(t *testing.T) { s := authorizer.NewBucketService(tt.fields.BucketService, nil) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) _, err := s.FindBucketByID(ctx, tt.args.id) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -192,7 +192,7 @@ func TestBucketService_FindBucket(t *testing.T) { s := authorizer.NewBucketService(tt.fields.BucketService, nil) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) _, err := s.FindBucket(ctx, influxdb.BucketFilter{}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -317,7 +317,7 @@ func TestBucketService_FindBuckets(t *testing.T) { s := authorizer.NewBucketService(tt.fields.BucketService, nil) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) buckets, _, err := s.FindBuckets(ctx, influxdb.BucketFilter{}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -432,7 +432,7 @@ func TestBucketService_UpdateBucket(t *testing.T) { s := authorizer.NewBucketService(tt.fields.BucketService, nil) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) _, err := s.UpdateBucket(ctx, tt.args.id, influxdb.BucketUpdate{}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -537,7 +537,7 @@ func TestBucketService_DeleteBucket(t *testing.T) { s := authorizer.NewBucketService(tt.fields.BucketService, nil) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) err := s.DeleteBucket(ctx, tt.args.id) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -619,7 +619,7 @@ func TestBucketService_CreateBucket(t *testing.T) { s := authorizer.NewBucketService(tt.fields.BucketService, nil) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) err := s.CreateBucket(ctx, &influxdb.Bucket{OrgID: tt.args.orgID}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) diff --git a/authorizer/check_test.go b/authorizer/check_test.go index f75644d22a..47f73d906b 100644 --- a/authorizer/check_test.go +++ b/authorizer/check_test.go @@ -112,7 +112,7 @@ func TestCheckService_FindCheckByID(t *testing.T) { s := authorizer.NewCheckService(tt.fields.CheckService, mock.NewUserResourceMappingService(), mock.NewOrganizationService()) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) _, err := s.FindCheckByID(ctx, tt.args.id) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -258,7 +258,7 @@ func TestCheckService_FindChecks(t *testing.T) { s := authorizer.NewCheckService(tt.fields.CheckService, mock.NewUserResourceMappingService(), mock.NewOrganizationService()) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) ts, _, err := s.FindChecks(ctx, influxdb.CheckFilter{}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -381,7 +381,7 @@ func TestCheckService_UpdateCheck(t *testing.T) { s := authorizer.NewCheckService(tt.fields.CheckService, mock.NewUserResourceMappingService(), mock.NewOrganizationService()) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) cc := influxdb.CheckCreate{ Check: &check.Deadman{}, @@ -505,7 +505,7 @@ func TestCheckService_PatchCheck(t *testing.T) { s := authorizer.NewCheckService(tt.fields.CheckService, mock.NewUserResourceMappingService(), mock.NewOrganizationService()) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) _, err := s.PatchCheck(ctx, tt.args.id, influxdb.CheckUpdate{}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -614,7 +614,7 @@ func TestCheckService_DeleteCheck(t *testing.T) { s := authorizer.NewCheckService(tt.fields.CheckService, mock.NewUserResourceMappingService(), mock.NewOrganizationService()) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) err := s.DeleteCheck(ctx, tt.args.id) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -696,7 +696,7 @@ func TestCheckService_CreateCheck(t *testing.T) { s := authorizer.NewCheckService(tt.fields.CheckService, mock.NewUserResourceMappingService(), mock.NewOrganizationService()) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) c := &check.Deadman{ Base: check.Base{ diff --git a/authorizer/dashboard_test.go b/authorizer/dashboard_test.go index 101a55ab0d..78cbc58557 100644 --- a/authorizer/dashboard_test.go +++ b/authorizer/dashboard_test.go @@ -107,7 +107,7 @@ func TestDashboardService_FindDashboardByID(t *testing.T) { s := authorizer.NewDashboardService(tt.fields.DashboardService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) _, err := s.FindDashboardByID(ctx, tt.args.id) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -232,7 +232,7 @@ func TestDashboardService_FindDashboards(t *testing.T) { s := authorizer.NewDashboardService(tt.fields.DashboardService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) dashboards, _, err := s.FindDashboards(ctx, influxdb.DashboardFilter{}, influxdb.FindOptions{}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -347,7 +347,7 @@ func TestDashboardService_UpdateDashboard(t *testing.T) { s := authorizer.NewDashboardService(tt.fields.DashboardService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) _, err := s.UpdateDashboard(ctx, tt.args.id, influxdb.DashboardUpdate{}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -452,7 +452,7 @@ func TestDashboardService_DeleteDashboard(t *testing.T) { s := authorizer.NewDashboardService(tt.fields.DashboardService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) err := s.DeleteDashboard(ctx, tt.args.id) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -534,7 +534,7 @@ func TestDashboardService_CreateDashboard(t *testing.T) { s := authorizer.NewDashboardService(tt.fields.DashboardService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) err := s.CreateDashboard(ctx, &influxdb.Dashboard{OrganizationID: tt.args.orgID}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -652,7 +652,7 @@ func TestDashboardService_WriteDashboardCell(t *testing.T) { s := authorizer.NewDashboardService(tt.fields.DashboardService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) err := s.AddDashboardCell(ctx, 1, &influxdb.Cell{}, influxdb.AddDashboardCellOptions{}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -758,7 +758,7 @@ func TestDashboardService_FindDashboardCellView(t *testing.T) { s := authorizer.NewDashboardService(tt.fields.DashboardService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) _, err := s.GetDashboardCellView(ctx, 1, 1) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) diff --git a/authorizer/label_test.go b/authorizer/label_test.go index a835e07cc1..51b71f04b5 100644 --- a/authorizer/label_test.go +++ b/authorizer/label_test.go @@ -120,7 +120,7 @@ func TestLabelService_FindLabelByID(t *testing.T) { s := authorizer.NewLabelServiceWithOrg(tt.fields.LabelService, orgSvc) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) _, err := s.FindLabelByID(ctx, tt.args.id) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -275,7 +275,7 @@ func TestLabelService_FindLabels(t *testing.T) { s := authorizer.NewLabelServiceWithOrg(tt.fields.LabelService, orgSvc) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) labels, err := s.FindLabels(ctx, influxdb.LabelFilter{}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -383,7 +383,7 @@ func TestLabelService_UpdateLabel(t *testing.T) { s := authorizer.NewLabelServiceWithOrg(tt.fields.LabelService, orgSvc) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) _, err := s.UpdateLabel(ctx, tt.args.id, influxdb.LabelUpdate{}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -483,7 +483,7 @@ func TestLabelService_DeleteLabel(t *testing.T) { s := authorizer.NewLabelServiceWithOrg(tt.fields.LabelService, orgSvc) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) err := s.DeleteLabel(ctx, tt.args.id) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -587,7 +587,7 @@ func TestLabelService_CreateLabel(t *testing.T) { s := authorizer.NewLabelServiceWithOrg(tt.fields.LabelService, orgSvc) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) err := s.CreateLabel(ctx, &influxdb.Label{Name: "name", OrgID: orgOneInfluxID}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -819,7 +819,7 @@ func TestLabelService_FindResourceLabels(t *testing.T) { s := authorizer.NewLabelServiceWithOrg(tt.fields.LabelService, orgSvc) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) labels, err := s.FindResourceLabels(ctx, tt.args.filter) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -971,7 +971,7 @@ func TestLabelService_CreateLabelMapping(t *testing.T) { s := authorizer.NewLabelServiceWithOrg(tt.fields.LabelService, orgSvc) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) err := s.CreateLabelMapping(ctx, &tt.args.mapping) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -1119,7 +1119,7 @@ func TestLabelService_DeleteLabelMapping(t *testing.T) { s := authorizer.NewLabelServiceWithOrg(tt.fields.LabelService, orgSvc) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) err := s.DeleteLabelMapping(ctx, &tt.args.mapping) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) diff --git a/authorizer/notification_endpoint_test.go b/authorizer/notification_endpoint_test.go index dbe64ab4cb..58698c7a4f 100644 --- a/authorizer/notification_endpoint_test.go +++ b/authorizer/notification_endpoint_test.go @@ -114,7 +114,7 @@ func TestNotificationEndpointService_FindNotificationEndpointByID(t *testing.T) s := authorizer.NewNotificationEndpointService(tt.fields.NotificationEndpointService, mock.NewUserResourceMappingService(), mock.NewOrganizationService()) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) _, err := s.FindNotificationEndpointByID(ctx, tt.args.id) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -197,7 +197,7 @@ func TestNotificationEndpointService_FindNotificationEndpoints(t *testing.T) { mock.NewOrganizationService()) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) oid := influxdb.ID(10) edps, _, err := s.FindNotificationEndpoints(ctx, influxdb.NotificationEndpointFilter{OrgID: &oid}) @@ -323,7 +323,7 @@ func TestNotificationEndpointService_UpdateNotificationEndpoint(t *testing.T) { mock.NewOrganizationService()) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) _, err := s.UpdateNotificationEndpoint(ctx, tt.args.id, &endpoint.Slack{}, influxdb.ID(1)) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -443,7 +443,7 @@ func TestNotificationEndpointService_PatchNotificationEndpoint(t *testing.T) { mock.NewOrganizationService()) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) _, err := s.PatchNotificationEndpoint(ctx, tt.args.id, influxdb.NotificationEndpointUpdate{}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -554,7 +554,7 @@ func TestNotificationEndpointService_DeleteNotificationEndpoint(t *testing.T) { ) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) _, _, err := s.DeleteNotificationEndpoint(ctx, tt.args.id) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -661,7 +661,7 @@ func TestNotificationEndpointService_CreateNotificationEndpoint(t *testing.T) { mock.NewOrganizationService(), ) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) err := s.CreateNotificationEndpoint(ctx, &endpoint.Slack{ Base: endpoint.Base{ diff --git a/authorizer/notification_rule_test.go b/authorizer/notification_rule_test.go index e6380e91c3..a45f721b1f 100644 --- a/authorizer/notification_rule_test.go +++ b/authorizer/notification_rule_test.go @@ -112,7 +112,7 @@ func TestNotificationRuleStore_FindNotificationRuleByID(t *testing.T) { s := authorizer.NewNotificationRuleStore(tt.fields.NotificationRuleStore, mock.NewUserResourceMappingService(), mock.NewOrganizationService()) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) _, err := s.FindNotificationRuleByID(ctx, tt.args.id) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -258,7 +258,7 @@ func TestNotificationRuleStore_FindNotificationRules(t *testing.T) { s := authorizer.NewNotificationRuleStore(tt.fields.NotificationRuleStore, mock.NewUserResourceMappingService(), mock.NewOrganizationService()) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) ts, _, err := s.FindNotificationRules(ctx, influxdb.NotificationRuleFilter{}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -381,7 +381,7 @@ func TestNotificationRuleStore_UpdateNotificationRule(t *testing.T) { s := authorizer.NewNotificationRuleStore(tt.fields.NotificationRuleStore, mock.NewUserResourceMappingService(), mock.NewOrganizationService()) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) nrc := influxdb.NotificationRuleCreate{ NotificationRule: &rule.Slack{}, @@ -505,7 +505,7 @@ func TestNotificationRuleStore_PatchNotificationRule(t *testing.T) { s := authorizer.NewNotificationRuleStore(tt.fields.NotificationRuleStore, mock.NewUserResourceMappingService(), mock.NewOrganizationService()) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) _, err := s.PatchNotificationRule(ctx, tt.args.id, influxdb.NotificationRuleUpdate{}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -614,7 +614,7 @@ func TestNotificationRuleStore_DeleteNotificationRule(t *testing.T) { s := authorizer.NewNotificationRuleStore(tt.fields.NotificationRuleStore, mock.NewUserResourceMappingService(), mock.NewOrganizationService()) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) err := s.DeleteNotificationRule(ctx, tt.args.id) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -696,7 +696,7 @@ func TestNotificationRuleStore_CreateNotificationRule(t *testing.T) { s := authorizer.NewNotificationRuleStore(tt.fields.NotificationRuleStore, mock.NewUserResourceMappingService(), mock.NewOrganizationService()) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) nr := &rule.Slack{ Base: rule.Base{ diff --git a/authorizer/org_test.go b/authorizer/org_test.go index 4e37a81c79..5a539825b3 100644 --- a/authorizer/org_test.go +++ b/authorizer/org_test.go @@ -105,8 +105,7 @@ func TestOrgService_FindOrganizationByID(t *testing.T) { s := authorizer.NewOrgService(tt.fields.OrgService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) - + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) _, err := s.FindOrganizationByID(ctx, tt.args.id) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) }) @@ -188,7 +187,7 @@ func TestOrgService_FindOrganization(t *testing.T) { s := authorizer.NewOrgService(tt.fields.OrgService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) _, err := s.FindOrganization(ctx, influxdb.OrganizationFilter{}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -298,7 +297,7 @@ func TestOrgService_FindOrganizations(t *testing.T) { s := authorizer.NewOrgService(tt.fields.OrgService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) orgs, _, err := s.FindOrganizations(ctx, influxdb.OrganizationFilter{}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -388,7 +387,7 @@ func TestOrgService_UpdateOrganization(t *testing.T) { s := authorizer.NewOrgService(tt.fields.OrgService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) _, err := s.UpdateOrganization(ctx, tt.args.id, influxdb.OrganizationUpdate{}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -470,7 +469,7 @@ func TestOrgService_DeleteOrganization(t *testing.T) { s := authorizer.NewOrgService(tt.fields.OrgService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) err := s.DeleteOrganization(ctx, tt.args.id) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -548,7 +547,7 @@ func TestOrgService_CreateOrganization(t *testing.T) { s := authorizer.NewOrgService(tt.fields.OrgService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) err := s.CreateOrganization(ctx, &influxdb.Organization{}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) diff --git a/authorizer/password_test.go b/authorizer/password_test.go index ceb94b2196..ac1754541e 100644 --- a/authorizer/password_test.go +++ b/authorizer/password_test.go @@ -30,9 +30,7 @@ func TestPasswordService(t *testing.T) { } s := authorizer.NewPasswordService(fakeSVC) - ctx := icontext.SetAuthorizer(context.Background(), &Authorizer{ - Permissions: []influxdb.Permission{permission}, - }) + ctx := icontext.SetAuthorizer(context.Background(), mock.NewMockAuthorizer(false, []influxdb.Permission{permission})) err := s.SetPassword(ctx, 1, "password") require.NoError(t, err) @@ -90,9 +88,7 @@ func TestPasswordService(t *testing.T) { } s := authorizer.NewPasswordService(fakeSVC) - ctx := icontext.SetAuthorizer(context.Background(), &Authorizer{ - Permissions: []influxdb.Permission{tt.badPermission}, - }) + ctx := icontext.SetAuthorizer(context.Background(), mock.NewMockAuthorizer(false, []influxdb.Permission{tt.badPermission})) err := s.SetPassword(ctx, goodUserID, "password") require.Error(t, err) diff --git a/authorizer/scraper_test.go b/authorizer/scraper_test.go index 66bf90031e..7622cc7656 100644 --- a/authorizer/scraper_test.go +++ b/authorizer/scraper_test.go @@ -107,7 +107,7 @@ func TestScraperTargetStoreService_GetTargetByID(t *testing.T) { s := authorizer.NewScraperTargetStoreService(tt.fields.ScraperTargetStoreService, mock.NewUserResourceMappingService(), mock.NewOrganizationService()) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) _, err := s.GetTargetByID(ctx, tt.args.id) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -232,7 +232,7 @@ func TestScraperTargetStoreService_ListTargets(t *testing.T) { mock.NewOrganizationService()) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) ts, err := s.ListTargets(ctx, influxdb.ScraperTargetFilter{}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -402,7 +402,7 @@ func TestScraperTargetStoreService_UpdateTarget(t *testing.T) { mock.NewOrganizationService()) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) _, err := s.UpdateTarget(ctx, &influxdb.ScraperTarget{ID: tt.args.id, BucketID: tt.args.bucketID}, influxdb.ID(1)) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -508,7 +508,7 @@ func TestScraperTargetStoreService_RemoveTarget(t *testing.T) { mock.NewOrganizationService()) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) err := s.RemoveTarget(ctx, tt.args.id) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -648,7 +648,7 @@ func TestScraperTargetStoreService_AddTarget(t *testing.T) { mock.NewOrganizationService()) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) err := s.AddTarget(ctx, &influxdb.ScraperTarget{OrgID: tt.args.orgID, BucketID: tt.args.bucketID}, influxdb.ID(1)) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) diff --git a/authorizer/secret_test.go b/authorizer/secret_test.go index da076048f5..34c7664e88 100644 --- a/authorizer/secret_test.go +++ b/authorizer/secret_test.go @@ -141,7 +141,7 @@ func TestSecretService_LoadSecret(t *testing.T) { s := authorizer.NewSecretService(tt.fields.SecretService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) _, err := s.LoadSecret(ctx, tt.args.org, tt.args.key) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -267,7 +267,7 @@ func TestSecretService_GetSecretKeys(t *testing.T) { s := authorizer.NewSecretService(tt.fields.SecretService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) secrets, err := s.GetSecretKeys(ctx, tt.args.org) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -357,7 +357,7 @@ func TestSecretService_PatchSecrets(t *testing.T) { s := authorizer.NewSecretService(tt.fields.SecretService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) patches := make(map[string]string) err := s.PatchSecrets(ctx, tt.args.org, patches) @@ -444,7 +444,7 @@ func TestSecretService_DeleteSecret(t *testing.T) { s := authorizer.NewSecretService(tt.fields.SecretService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) err := s.DeleteSecret(ctx, tt.args.org) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -526,7 +526,7 @@ func TestSecretService_PutSecret(t *testing.T) { s := authorizer.NewSecretService(tt.fields.SecretService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) err := s.PutSecret(ctx, tt.args.orgID, "", "") influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -688,7 +688,7 @@ func TestSecretService_PutSecrets(t *testing.T) { s := authorizer.NewSecretService(tt.fields.SecretService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) secrets := make(map[string]string) err := s.PutSecrets(ctx, tt.args.orgID, secrets) diff --git a/authorizer/source_test.go b/authorizer/source_test.go index ee1b9db8bb..1cecbfbca3 100644 --- a/authorizer/source_test.go +++ b/authorizer/source_test.go @@ -104,7 +104,7 @@ func TestSourceService_DefaultSource(t *testing.T) { s := authorizer.NewSourceService(tt.fields.SourceService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) _, err := s.DefaultSource(ctx) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -192,7 +192,7 @@ func TestSourceService_FindSourceByID(t *testing.T) { s := authorizer.NewSourceService(tt.fields.SourceService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) _, err := s.FindSourceByID(ctx, tt.args.id) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -316,7 +316,7 @@ func TestSourceService_FindSources(t *testing.T) { s := authorizer.NewSourceService(tt.fields.SourceService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) sources, _, err := s.FindSources(ctx, influxdb.DefaultSourceFindOptions) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -431,7 +431,7 @@ func TestSourceService_UpdateSource(t *testing.T) { s := authorizer.NewSourceService(tt.fields.SourceService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) _, err := s.UpdateSource(ctx, tt.args.id, influxdb.SourceUpdate{}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -536,7 +536,7 @@ func TestSourceService_DeleteSource(t *testing.T) { s := authorizer.NewSourceService(tt.fields.SourceService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) err := s.DeleteSource(ctx, tt.args.id) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -618,7 +618,7 @@ func TestSourceService_CreateSource(t *testing.T) { s := authorizer.NewSourceService(tt.fields.SourceService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) err := s.CreateSource(ctx, &influxdb.Source{OrganizationID: tt.args.orgID}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) diff --git a/authorizer/telegraf_test.go b/authorizer/telegraf_test.go index 02c3556a70..64a00581fc 100644 --- a/authorizer/telegraf_test.go +++ b/authorizer/telegraf_test.go @@ -107,7 +107,7 @@ func TestTelegrafConfigStore_FindTelegrafConfigByID(t *testing.T) { s := authorizer.NewTelegrafConfigService(tt.fields.TelegrafConfigStore, mock.NewUserResourceMappingService()) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) _, err := s.FindTelegrafConfigByID(ctx, tt.args.id) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -231,7 +231,7 @@ func TestTelegrafConfigStore_FindTelegrafConfigs(t *testing.T) { s := authorizer.NewTelegrafConfigService(tt.fields.TelegrafConfigStore, mock.NewUserResourceMappingService()) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) ts, _, err := s.FindTelegrafConfigs(ctx, influxdb.TelegrafConfigFilter{}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -346,7 +346,7 @@ func TestTelegrafConfigStore_UpdateTelegrafConfig(t *testing.T) { s := authorizer.NewTelegrafConfigService(tt.fields.TelegrafConfigStore, mock.NewUserResourceMappingService()) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) _, err := s.UpdateTelegrafConfig(ctx, tt.args.id, &influxdb.TelegrafConfig{}, influxdb.ID(1)) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -451,7 +451,7 @@ func TestTelegrafConfigStore_DeleteTelegrafConfig(t *testing.T) { s := authorizer.NewTelegrafConfigService(tt.fields.TelegrafConfigStore, mock.NewUserResourceMappingService()) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) err := s.DeleteTelegrafConfig(ctx, tt.args.id) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -533,7 +533,7 @@ func TestTelegrafConfigStore_CreateTelegrafConfig(t *testing.T) { s := authorizer.NewTelegrafConfigService(tt.fields.TelegrafConfigStore, mock.NewUserResourceMappingService()) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) err := s.CreateTelegrafConfig(ctx, &influxdb.TelegrafConfig{OrgID: tt.args.orgID}, influxdb.ID(1)) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) diff --git a/authorizer/urm_test.go b/authorizer/urm_test.go index ee659e10cd..bc1da8cf1a 100644 --- a/authorizer/urm_test.go +++ b/authorizer/urm_test.go @@ -131,7 +131,7 @@ func TestURMService_FindUserResourceMappings(t *testing.T) { s := authorizer.NewURMService(tt.fields.OrgService, tt.fields.UserResourceMappingService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) urms, _, err := s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -241,7 +241,7 @@ func TestURMService_WriteUserResourceMapping(t *testing.T) { s := authorizer.NewURMService(tt.fields.OrgService, tt.fields.UserResourceMappingService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) t.Run("create urm", func(t *testing.T) { err := s.CreateUserResourceMapping(ctx, &influxdb.UserResourceMapping{ResourceType: influxdb.BucketsResourceType, ResourceID: 1}) diff --git a/authorizer/user_test.go b/authorizer/user_test.go index 7bfabae249..0f7e125816 100644 --- a/authorizer/user_test.go +++ b/authorizer/user_test.go @@ -105,7 +105,7 @@ func TestUserService_FindUserByID(t *testing.T) { s := authorizer.NewUserService(tt.fields.UserService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) _, err := s.FindUserByID(ctx, tt.args.id) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -188,7 +188,7 @@ func TestUserService_FindUser(t *testing.T) { s := authorizer.NewUserService(tt.fields.UserService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) _, err := s.FindUser(ctx, influxdb.UserFilter{}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -298,7 +298,7 @@ func TestUserService_FindUsers(t *testing.T) { s := authorizer.NewUserService(tt.fields.UserService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) users, _, err := s.FindUsers(ctx, influxdb.UserFilter{}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -388,7 +388,7 @@ func TestUserService_UpdateUser(t *testing.T) { s := authorizer.NewUserService(tt.fields.UserService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) _, err := s.UpdateUser(ctx, tt.args.id, influxdb.UserUpdate{}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -470,7 +470,7 @@ func TestUserService_DeleteUser(t *testing.T) { s := authorizer.NewUserService(tt.fields.UserService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) err := s.DeleteUser(ctx, tt.args.id) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -548,7 +548,7 @@ func TestUserService_CreateUser(t *testing.T) { s := authorizer.NewUserService(tt.fields.UserService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) err := s.CreateUser(ctx, &influxdb.User{}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) diff --git a/authorizer/util_test.go b/authorizer/util_test.go deleted file mode 100644 index a8a3f69960..0000000000 --- a/authorizer/util_test.go +++ /dev/null @@ -1,24 +0,0 @@ -package authorizer_test - -import "github.com/influxdata/influxdb/v2" - -// Authorizer is mock authorizer that can be used in testing. -type Authorizer struct { - Permissions []influxdb.Permission -} - -func (a *Authorizer) Allowed(p influxdb.Permission) bool { - return influxdb.PermissionAllowed(p, a.Permissions) -} - -func (a *Authorizer) Identifier() influxdb.ID { - return 1 -} - -func (a *Authorizer) GetUserID() influxdb.ID { - return 2 -} - -func (a *Authorizer) Kind() string { - return "mock" -} diff --git a/authorizer/variable_test.go b/authorizer/variable_test.go index d87b239f98..c5cf261f01 100644 --- a/authorizer/variable_test.go +++ b/authorizer/variable_test.go @@ -107,7 +107,7 @@ func TestVariableService_FindVariableByID(t *testing.T) { s := authorizer.NewVariableService(tt.fields.VariableService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) _, err := s.FindVariableByID(ctx, tt.args.id) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -231,7 +231,7 @@ func TestVariableService_FindVariables(t *testing.T) { s := authorizer.NewVariableService(tt.fields.VariableService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) variables, err := s.FindVariables(ctx, influxdb.VariableFilter{}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -346,7 +346,7 @@ func TestVariableService_UpdateVariable(t *testing.T) { s := authorizer.NewVariableService(tt.fields.VariableService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) _, err := s.UpdateVariable(ctx, tt.args.id, &influxdb.VariableUpdate{}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -458,7 +458,7 @@ func TestVariableService_ReplaceVariable(t *testing.T) { s := authorizer.NewVariableService(tt.fields.VariableService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) err := s.ReplaceVariable(ctx, &tt.args.variable) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -563,7 +563,7 @@ func TestVariableService_DeleteVariable(t *testing.T) { s := authorizer.NewVariableService(tt.fields.VariableService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) err := s.DeleteVariable(ctx, tt.args.id) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) @@ -645,7 +645,7 @@ func TestVariableService_CreateVariable(t *testing.T) { s := authorizer.NewVariableService(tt.fields.VariableService) ctx := context.Background() - ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}}) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) err := s.CreateVariable(ctx, &influxdb.Variable{OrganizationID: tt.args.orgID}) influxdbtesting.ErrorsEqual(t, err, tt.wants.err) diff --git a/cmd/influxd/launcher/launcher.go b/cmd/influxd/launcher/launcher.go index f7650ae1d6..173cf1ce6e 100644 --- a/cmd/influxd/launcher/launcher.go +++ b/cmd/influxd/launcher/launcher.go @@ -610,6 +610,7 @@ func (m *Launcher) run(ctx context.Context) (err error) { return err } + userSvcForAuth := userSvc if m.enableNewMetaStore { var ts platform.TenantService if m.newMetaStoreReadOnly { @@ -624,12 +625,13 @@ func (m *Launcher) run(ctx context.Context) (err error) { } else { ts = tenant.NewService(store) } + userSvcForAuth = ts - bucketSvc = tenant.NewBucketLogger(m.log.With(zap.String("store", "new")), tenant.NewBucketMetrics(m.reg, ts, tenant.WithSuffix("new"))) - orgSvc = tenant.NewOrgLogger(m.log.With(zap.String("store", "new")), tenant.NewOrgMetrics(m.reg, ts, tenant.WithSuffix("new"))) - userResourceSvc = tenant.NewURMLogger(m.log.With(zap.String("store", "new")), tenant.NewUrmMetrics(m.reg, ts, tenant.WithSuffix("new"))) - userSvc = tenant.NewUserLogger(m.log.With(zap.String("store", "new")), tenant.NewUserMetrics(m.reg, ts, tenant.WithSuffix("new"))) - passwdsSvc = tenant.NewPasswordLogger(m.log.With(zap.String("store", "new")), tenant.NewPasswordMetrics(m.reg, ts, tenant.WithSuffix("new"))) + userSvc = tenant.NewAuthedUserService(tenant.NewUserLogger(m.log.With(zap.String("store", "new")), tenant.NewUserMetrics(m.reg, ts, tenant.WithSuffix("new")))) + orgSvc = tenant.NewAuthedOrgService(tenant.NewOrgLogger(m.log.With(zap.String("store", "new")), tenant.NewOrgMetrics(m.reg, ts, tenant.WithSuffix("new")))) + userResourceSvc = tenant.NewAuthedURMService(ts, tenant.NewURMLogger(m.log.With(zap.String("store", "new")), tenant.NewUrmMetrics(m.reg, ts, tenant.WithSuffix("new")))) + bucketSvc = tenant.NewAuthedBucketService(tenant.NewBucketLogger(m.log.With(zap.String("store", "new")), tenant.NewBucketMetrics(m.reg, ts, tenant.WithSuffix("new"))), userResourceSvc) + passwdsSvc = tenant.NewAuthedPasswordService(tenant.NewPasswordLogger(m.log.With(zap.String("store", "new")), tenant.NewPasswordMetrics(m.reg, ts, tenant.WithSuffix("new")))) } switch m.secretStore { @@ -953,7 +955,7 @@ func (m *Launcher) run(ctx context.Context) (err error) { } { - platformHandler := http.NewPlatformHandler(m.apibackend, http.WithResourceHandler(pkgHTTPServer), http.WithResourceHandler(onboardHTTPServer)) + platformHandler := http.NewPlatformHandler(m.apibackend, userSvcForAuth, http.WithResourceHandler(pkgHTTPServer), http.WithResourceHandler(onboardHTTPServer)) httpLogger := m.log.With(zap.String("service", "http")) m.httpServer.Handler = http.NewHandlerFromRegistry( diff --git a/cmd/influxd/launcher/launcher_helpers.go b/cmd/influxd/launcher/launcher_helpers.go index e4c28acd84..1ac5907dab 100644 --- a/cmd/influxd/launcher/launcher_helpers.go +++ b/cmd/influxd/launcher/launcher_helpers.go @@ -117,6 +117,7 @@ func (tl *TestLauncher) Setup() error { } tl.User = results.User + fmt.Println(tl.User) tl.Org = results.Org tl.Bucket = results.Bucket tl.Auth = results.Auth @@ -223,7 +224,7 @@ func (tl *TestLauncher) MustExecuteQuery(query string) *QueryResults { // ExecuteQuery executes the provided query against the ith query node. // Callers of ExecuteQuery must call Done on the returned QueryResults. func (tl *TestLauncher) ExecuteQuery(q string) (*QueryResults, error) { - ctx := influxdbcontext.SetAuthorizer(context.Background(), &mock.Authorization{}) + ctx := influxdbcontext.SetAuthorizer(context.Background(), mock.NewMockAuthorizer(true, nil)) fq, err := tl.QueryController().Query(ctx, &query.Request{ Authorization: tl.Auth, OrganizationID: tl.Auth.OrgID, diff --git a/http/document_service_test.go b/http/document_service_test.go index 6193c0e185..e9f82dd886 100644 --- a/http/document_service_test.go +++ b/http/document_service_test.go @@ -33,7 +33,7 @@ func setup(t *testing.T) (func(auth influxdb.Authorizer) *httptest.Server, func( ctx := context.Background() // Need this to make resource creation work. // We are not testing authorization in the setup. - ctx = icontext.SetAuthorizer(ctx, mock.Authorization{}) + ctx = icontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(true, nil)) if err := svc.Initialize(ctx); err != nil { t.Fatal(err) } diff --git a/http/platform_handler.go b/http/platform_handler.go index 77773104bd..5c04e0fa9f 100644 --- a/http/platform_handler.go +++ b/http/platform_handler.go @@ -4,6 +4,7 @@ import ( "net/http" "strings" + "github.com/influxdata/influxdb/v2" kithttp "github.com/influxdata/influxdb/v2/kit/transport/http" ) @@ -15,13 +16,13 @@ type PlatformHandler struct { } // NewPlatformHandler returns a platform handler that serves the API and associated assets. -func NewPlatformHandler(b *APIBackend, opts ...APIHandlerOptFn) *PlatformHandler { +func NewPlatformHandler(b *APIBackend, us influxdb.UserService, opts ...APIHandlerOptFn) *PlatformHandler { h := NewAuthenticationHandler(b.Logger, b.HTTPErrorHandler) h.Handler = NewAPIHandler(b, opts...) h.AuthorizationService = b.AuthorizationService h.SessionService = b.SessionService h.SessionRenewDisabled = b.SessionRenewDisabled - h.UserService = b.UserService + h.UserService = us h.RegisterNoAuthRoute("GET", "/api/v2") h.RegisterNoAuthRoute("POST", "/api/v2/signin") diff --git a/mock/authorization.go b/mock/authorization.go index 9e9bed0eb6..f84fb09293 100644 --- a/mock/authorization.go +++ b/mock/authorization.go @@ -1,33 +1,42 @@ package mock import ( - platform "github.com/influxdata/influxdb/v2" + influxdb "github.com/influxdata/influxdb/v2" ) -// Authorization is an Authorizer that always allows everything -type Authorization struct { +// Authorizer is an Authorizer for testing that can allow everything or use specific permissions +type Authorizer struct { + Permissions []influxdb.Permission + AllowAll bool } -func (Authorization) Allowed(p platform.Permission) bool { - return true -} - -func (Authorization) Identifier() platform.ID { - return mustID("beefdeaddeadbeef") -} - -func (Authorization) GetUserID() platform.ID { - return mustID("deadbeefbeefdead") -} - -func (Authorization) Kind() string { - return "mock-authorizer" -} - -func mustID(str string) platform.ID { - id, err := platform.IDFromString(str) - if err != nil { - panic(err) +func NewMockAuthorizer(allowAll bool, permissions []influxdb.Permission) *Authorizer { + if allowAll { + return &Authorizer{ + AllowAll: true, + } + } + return &Authorizer{ + AllowAll: false, + Permissions: permissions, } - return *id +} + +func (a *Authorizer) Allowed(p influxdb.Permission) bool { + if a.AllowAll { + return true + } + return influxdb.PermissionAllowed(p, a.Permissions) +} + +func (a *Authorizer) Identifier() influxdb.ID { + return 1 +} + +func (a *Authorizer) GetUserID() influxdb.ID { + return 2 +} + +func (Authorizer) Kind() string { + return "mock" } diff --git a/query/stdlib/testing/end_to_end_test.go b/query/stdlib/testing/end_to_end_test.go index 32d6a8eed5..f1409172c7 100644 --- a/query/stdlib/testing/end_to_end_test.go +++ b/query/stdlib/testing/end_to_end_test.go @@ -24,7 +24,7 @@ import ( ) // Default context. -var ctx = influxdbcontext.SetAuthorizer(context.Background(), &mock.Authorization{}) +var ctx = influxdbcontext.SetAuthorizer(context.Background(), mock.NewMockAuthorizer(true, nil)) func init() { flux.FinalizeBuiltIns() diff --git a/tenant/error.go b/tenant/error.go index 7d214e575f..e0b37c4fd1 100644 --- a/tenant/error.go +++ b/tenant/error.go @@ -38,6 +38,11 @@ var ( Code: influxdb.EEmptyValue, Msg: "onboard failed, missing value", } + + ErrNotFound = &influxdb.Error{ + Code: influxdb.ENotFound, + Msg: "not found", + } ) // ErrCorruptID the ID stored in the Store is corrupt. diff --git a/tenant/http_server.go b/tenant/http_server.go index 72ade9324a..7ef50432b5 100644 --- a/tenant/http_server.go +++ b/tenant/http_server.go @@ -1,13 +1,20 @@ package tenant import ( + "context" "fmt" "net/http" "strconv" + "github.com/go-chi/chi" "github.com/influxdata/influxdb/v2" + kit "github.com/influxdata/influxdb/v2/kit/transport/http" ) +type tenantContext string + +const ctxOrgKey tenantContext = "orgID" + // findOptionsParams converts find options into a paramiterizated key pair func findOptionParams(opts ...influxdb.FindOptions) [][2]string { var out [][2]string @@ -77,3 +84,37 @@ func decodeFindOptions(r *http.Request) (*influxdb.FindOptions, error) { return opts, nil } + +// ValidResource make sure a resource exists when a sub system needs to be mounted to an api +func ValidResource(api *kit.API, lookupOrgByResourceID func(context.Context, influxdb.ID) (influxdb.ID, error)) kit.Middleware { + return func(next http.Handler) http.Handler { + fn := func(w http.ResponseWriter, r *http.Request) { + statusW := kit.NewStatusResponseWriter(w) + id, err := influxdb.IDFromString(chi.URLParam(r, "id")) + if err != nil { + api.Err(w, ErrCorruptID(err)) + return + } + + ctx := r.Context() + + orgID, err := lookupOrgByResourceID(ctx, *id) + if err != nil { + api.Err(w, err) + return + } + + next.ServeHTTP(statusW, r.WithContext(context.WithValue(ctx, ctxOrgKey, orgID))) + } + return http.HandlerFunc(fn) + } +} + +func orgIDFromContext(ctx context.Context) *influxdb.ID { + v := ctx.Value(ctxOrgKey) + if v == nil { + return nil + } + id := v.(influxdb.ID) + return &id +} diff --git a/tenant/http_server_bucket.go b/tenant/http_server_bucket.go index c6f49fc83a..6810688938 100644 --- a/tenant/http_server_bucket.go +++ b/tenant/http_server_bucket.go @@ -52,9 +52,10 @@ func NewHTTPBucketHandler(log *zap.Logger, bucketSvc influxdb.BucketService, urm r.Delete("/", svr.handleDeleteBucket) // mount embedded resources - r.Mount("/members", urmHandler) - r.Mount("/owners", urmHandler) - r.Mount("/labels", labelHandler) + mountableRouter := r.With(ValidResource(svr.api, svr.lookupOrgByBucketID)) + mountableRouter.Mount("/members", urmHandler) + mountableRouter.Mount("/owners", urmHandler) + mountableRouter.Mount("/labels", labelHandler) }) }) @@ -465,6 +466,14 @@ func (h *BucketHandler) handlePatchBucket(w http.ResponseWriter, r *http.Request h.api.Respond(w, http.StatusOK, NewBucketResponse(b)) } +func (h *BucketHandler) lookupOrgByBucketID(ctx context.Context, id influxdb.ID) (influxdb.ID, error) { + b, err := h.bucketSvc.FindBucketByID(ctx, id) + if err != nil { + return 0, err + } + return b.OrgID, nil +} + // validBucketName reports any errors with bucket names func validBucketName(bucket *influxdb.Bucket) error { // names starting with an underscore are reserved for system buckets diff --git a/tenant/http_server_org.go b/tenant/http_server_org.go index 841c9b343e..5ffa690014 100644 --- a/tenant/http_server_org.go +++ b/tenant/http_server_org.go @@ -1,6 +1,7 @@ package tenant import ( + "context" "fmt" "net/http" @@ -52,10 +53,11 @@ func NewHTTPOrgHandler(log *zap.Logger, orgService influxdb.OrganizationService, r.Delete("/", svr.handleDeleteOrg) // mount embedded resources - r.Mount("/members", urm) - r.Mount("/owners", urm) - r.Mount("/labels", labelHandler) - r.Mount("/secrets", secretHandler) + mountableRouter := r.With(ValidResource(svr.api, svr.lookupOrgByID)) + mountableRouter.Mount("/members", urm) + mountableRouter.Mount("/owners", urm) + mountableRouter.Mount("/labels", labelHandler) + mountableRouter.Mount("/secrets", secretHandler) }) }) @@ -64,6 +66,7 @@ func NewHTTPOrgHandler(log *zap.Logger, orgService influxdb.OrganizationService, } type orgResponse struct { + Links map[string]string `json:"links"` influxdb.Organization } @@ -74,7 +77,8 @@ func newOrgResponse(o influxdb.Organization) orgResponse { } type orgsResponse struct { - Organizations []orgResponse `json:"orgs"` + Links map[string]string `json:"links"` + Organizations []orgResponse `json:"orgs"` } func newOrgsResponse(orgs []*influxdb.Organization) *orgsResponse { @@ -189,3 +193,12 @@ func (h *OrgHandler) handleDeleteOrg(w http.ResponseWriter, r *http.Request) { h.api.Respond(w, http.StatusNoContent, nil) } + +func (h *OrgHandler) lookupOrgByID(ctx context.Context, id influxdb.ID) (influxdb.ID, error) { + _, err := h.orgSvc.FindOrganizationByID(ctx, id) + if err != nil { + return 0, err + } + + return id, nil +} diff --git a/tenant/middleware_bucket_auth.go b/tenant/middleware_bucket_auth.go new file mode 100644 index 0000000000..afd594e39b --- /dev/null +++ b/tenant/middleware_bucket_auth.go @@ -0,0 +1,122 @@ +package tenant + +import ( + "context" + + "github.com/influxdata/influxdb/v2" + "github.com/influxdata/influxdb/v2/authorizer" + "github.com/influxdata/influxdb/v2/kit/tracing" +) + +var _ influxdb.BucketService = (*AuthedBucketService)(nil) + +// TODO (al): remove authorizer/bucket when the bucket service moves to tenant + +// AuthedBucketService wraps a influxdb.BucketService and authorizes actions +// against it appropriately. +type AuthedBucketService struct { + s influxdb.BucketService + u influxdb.UserResourceMappingService +} + +// NewAuthedBucketService constructs an instance of an authorizing bucket serivce. +func NewAuthedBucketService(s influxdb.BucketService, u influxdb.UserResourceMappingService) *AuthedBucketService { + return &AuthedBucketService{ + s: s, + u: u, + } +} + +// FindBucketByID checks to see if the authorizer on context has read access to the id provided. +func (s *AuthedBucketService) FindBucketByID(ctx context.Context, id influxdb.ID) (*influxdb.Bucket, error) { + span, ctx := tracing.StartSpanFromContext(ctx) + defer span.Finish() + + b, err := s.s.FindBucketByID(ctx, id) + if err != nil { + return nil, err + } + if _, _, err := authorizer.AuthorizeReadBucket(ctx, b.Type, b.ID, b.OrgID); err != nil { + return nil, err + } + return b, nil +} + +// FindBucketByName returns a bucket by name for a particular organization. +func (s *AuthedBucketService) FindBucketByName(ctx context.Context, orgID influxdb.ID, n string) (*influxdb.Bucket, error) { + span, ctx := tracing.StartSpanFromContext(ctx) + defer span.Finish() + + b, err := s.s.FindBucketByName(ctx, orgID, n) + if err != nil { + return nil, err + } + if _, _, err := authorizer.AuthorizeReadBucket(ctx, b.Type, b.ID, b.OrgID); err != nil { + return nil, err + } + return b, nil +} + +// FindBucket retrieves the bucket and checks to see if the authorizer on context has read access to the bucket. +func (s *AuthedBucketService) FindBucket(ctx context.Context, filter influxdb.BucketFilter) (*influxdb.Bucket, error) { + span, ctx := tracing.StartSpanFromContext(ctx) + defer span.Finish() + + b, err := s.s.FindBucket(ctx, filter) + if err != nil { + return nil, err + } + if _, _, err := authorizer.AuthorizeReadBucket(ctx, b.Type, b.ID, b.OrgID); err != nil { + return nil, err + } + return b, nil +} + +// FindBuckets retrieves all buckets that match the provided filter and then filters the list down to only the resources that are authorized. +func (s *AuthedBucketService) FindBuckets(ctx context.Context, filter influxdb.BucketFilter, opt ...influxdb.FindOptions) ([]*influxdb.Bucket, int, error) { + span, ctx := tracing.StartSpanFromContext(ctx) + defer span.Finish() + + // TODO: we'll likely want to push this operation into the database eventually since fetching the whole list of data + // will likely be expensive. + bs, _, err := s.s.FindBuckets(ctx, filter, opt...) + if err != nil { + return nil, 0, err + } + return authorizer.AuthorizeFindBuckets(ctx, bs) +} + +// CreateBucket checks to see if the authorizer on context has write access to the global buckets resource. +func (s *AuthedBucketService) CreateBucket(ctx context.Context, b *influxdb.Bucket) error { + span, ctx := tracing.StartSpanFromContext(ctx) + defer span.Finish() + + if _, _, err := authorizer.AuthorizeCreate(ctx, influxdb.BucketsResourceType, b.OrgID); err != nil { + return err + } + return s.s.CreateBucket(ctx, b) +} + +// UpdateBucket checks to see if the authorizer on context has write access to the bucket provided. +func (s *AuthedBucketService) UpdateBucket(ctx context.Context, id influxdb.ID, upd influxdb.BucketUpdate) (*influxdb.Bucket, error) { + b, err := s.s.FindBucketByID(ctx, id) + if err != nil { + return nil, err + } + if _, _, err := authorizer.AuthorizeWrite(ctx, influxdb.BucketsResourceType, id, b.OrgID); err != nil { + return nil, err + } + return s.s.UpdateBucket(ctx, id, upd) +} + +// DeleteBucket checks to see if the authorizer on context has write access to the bucket provided. +func (s *AuthedBucketService) DeleteBucket(ctx context.Context, id influxdb.ID) error { + b, err := s.s.FindBucketByID(ctx, id) + if err != nil { + return err + } + if _, _, err := authorizer.AuthorizeWrite(ctx, influxdb.BucketsResourceType, id, b.OrgID); err != nil { + return err + } + return s.s.DeleteBucket(ctx, id) +} diff --git a/tenant/middleware_bucket_auth_test.go b/tenant/middleware_bucket_auth_test.go new file mode 100644 index 0000000000..976c1a7966 --- /dev/null +++ b/tenant/middleware_bucket_auth_test.go @@ -0,0 +1,628 @@ +package tenant_test + +import ( + "bytes" + "context" + "sort" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/influxdata/influxdb/v2" + influxdbcontext "github.com/influxdata/influxdb/v2/context" + "github.com/influxdata/influxdb/v2/mock" + "github.com/influxdata/influxdb/v2/tenant" + influxdbtesting "github.com/influxdata/influxdb/v2/testing" +) + +var bucketCmpOptions = cmp.Options{ + cmp.Comparer(func(x, y []byte) bool { + return bytes.Equal(x, y) + }), + cmp.Transformer("Sort", func(in []*influxdb.Bucket) []*influxdb.Bucket { + out := append([]*influxdb.Bucket(nil), in...) // Copy input to avoid mutating it + sort.Slice(out, func(i, j int) bool { + return out[i].ID.String() > out[j].ID.String() + }) + return out + }), +} + +func TestBucketService_FindBucketByID(t *testing.T) { + type fields struct { + BucketService influxdb.BucketService + } + type args struct { + permission influxdb.Permission + id influxdb.ID + } + type wants struct { + err error + } + + tests := []struct { + name string + fields fields + args args + wants wants + }{ + { + name: "authorized to access id", + fields: fields{ + BucketService: &mock.BucketService{ + FindBucketByIDFn: func(ctx context.Context, id influxdb.ID) (*influxdb.Bucket, error) { + return &influxdb.Bucket{ + ID: id, + OrgID: 10, + }, nil + }, + }, + }, + args: args{ + permission: influxdb.Permission{ + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.BucketsResourceType, + ID: influxdbtesting.IDPtr(1), + }, + }, + id: 1, + }, + wants: wants{ + err: nil, + }, + }, + { + name: "unauthorized to access id", + fields: fields{ + BucketService: &mock.BucketService{ + FindBucketByIDFn: func(ctx context.Context, id influxdb.ID) (*influxdb.Bucket, error) { + return &influxdb.Bucket{ + ID: id, + OrgID: 10, + }, nil + }, + }, + }, + args: args{ + permission: influxdb.Permission{ + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.BucketsResourceType, + ID: influxdbtesting.IDPtr(2), + }, + }, + id: 1, + }, + wants: wants{ + err: &influxdb.Error{ + Msg: "read:orgs/000000000000000a/buckets/0000000000000001 is unauthorized", + Code: influxdb.EUnauthorized, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := tenant.NewAuthedBucketService(tt.fields.BucketService, nil) + + ctx := context.Background() + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) + + _, err := s.FindBucketByID(ctx, tt.args.id) + influxdbtesting.ErrorsEqual(t, err, tt.wants.err) + }) + } +} + +func TestBucketService_FindBucket(t *testing.T) { + type fields struct { + BucketService influxdb.BucketService + } + type args struct { + permission influxdb.Permission + } + type wants struct { + err error + } + + tests := []struct { + name string + fields fields + args args + wants wants + }{ + { + name: "authorized to access bucket", + fields: fields{ + BucketService: &mock.BucketService{ + FindBucketFn: func(ctx context.Context, filter influxdb.BucketFilter) (*influxdb.Bucket, error) { + return &influxdb.Bucket{ + ID: 1, + OrgID: 10, + }, nil + }, + }, + }, + args: args{ + permission: influxdb.Permission{ + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.BucketsResourceType, + ID: influxdbtesting.IDPtr(1), + }, + }, + }, + wants: wants{ + err: nil, + }, + }, + { + name: "unauthorized to access bucket", + fields: fields{ + BucketService: &mock.BucketService{ + FindBucketFn: func(ctx context.Context, filter influxdb.BucketFilter) (*influxdb.Bucket, error) { + return &influxdb.Bucket{ + ID: 1, + OrgID: 10, + }, nil + }, + }, + }, + args: args{ + permission: influxdb.Permission{ + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.BucketsResourceType, + ID: influxdbtesting.IDPtr(2), + }, + }, + }, + wants: wants{ + err: &influxdb.Error{ + Msg: "read:orgs/000000000000000a/buckets/0000000000000001 is unauthorized", + Code: influxdb.EUnauthorized, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := tenant.NewAuthedBucketService(tt.fields.BucketService, nil) + + ctx := context.Background() + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) + + _, err := s.FindBucket(ctx, influxdb.BucketFilter{}) + influxdbtesting.ErrorsEqual(t, err, tt.wants.err) + }) + } +} + +func TestBucketService_FindBuckets(t *testing.T) { + type fields struct { + BucketService influxdb.BucketService + } + type args struct { + permission influxdb.Permission + } + type wants struct { + err error + buckets []*influxdb.Bucket + } + + tests := []struct { + name string + fields fields + args args + wants wants + }{ + { + name: "authorized to see all buckets", + fields: fields{ + BucketService: &mock.BucketService{ + FindBucketsFn: func(ctx context.Context, filter influxdb.BucketFilter, opt ...influxdb.FindOptions) ([]*influxdb.Bucket, int, error) { + return []*influxdb.Bucket{ + { + ID: 1, + OrgID: 10, + }, + { + ID: 2, + OrgID: 10, + }, + { + ID: 3, + OrgID: 11, + }, + }, 3, nil + }, + }, + }, + args: args{ + permission: influxdb.Permission{ + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.BucketsResourceType, + }, + }, + }, + wants: wants{ + buckets: []*influxdb.Bucket{ + { + ID: 1, + OrgID: 10, + }, + { + ID: 2, + OrgID: 10, + }, + { + ID: 3, + OrgID: 11, + }, + }, + }, + }, + { + name: "authorized to access a single orgs buckets", + fields: fields{ + BucketService: &mock.BucketService{ + + FindBucketsFn: func(ctx context.Context, filter influxdb.BucketFilter, opt ...influxdb.FindOptions) ([]*influxdb.Bucket, int, error) { + return []*influxdb.Bucket{ + { + ID: 1, + OrgID: 10, + }, + { + ID: 2, + OrgID: 10, + }, + { + ID: 3, + OrgID: 11, + }, + }, 3, nil + }, + }, + }, + args: args{ + permission: influxdb.Permission{ + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.BucketsResourceType, + OrgID: influxdbtesting.IDPtr(10), + }, + }, + }, + wants: wants{ + buckets: []*influxdb.Bucket{ + { + ID: 1, + OrgID: 10, + }, + { + ID: 2, + OrgID: 10, + }, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := tenant.NewAuthedBucketService(tt.fields.BucketService, nil) + + ctx := context.Background() + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) + + buckets, _, err := s.FindBuckets(ctx, influxdb.BucketFilter{}) + influxdbtesting.ErrorsEqual(t, err, tt.wants.err) + + if diff := cmp.Diff(buckets, tt.wants.buckets, bucketCmpOptions...); diff != "" { + t.Errorf("buckets are different -got/+want\ndiff %s", diff) + } + }) + } +} + +func TestBucketService_UpdateBucket(t *testing.T) { + type fields struct { + BucketService influxdb.BucketService + } + type args struct { + id influxdb.ID + permissions []influxdb.Permission + } + type wants struct { + err error + } + + tests := []struct { + name string + fields fields + args args + wants wants + }{ + { + name: "authorized to update bucket", + fields: fields{ + BucketService: &mock.BucketService{ + FindBucketByIDFn: func(ctc context.Context, id influxdb.ID) (*influxdb.Bucket, error) { + return &influxdb.Bucket{ + ID: 1, + OrgID: 10, + }, nil + }, + UpdateBucketFn: func(ctx context.Context, id influxdb.ID, upd influxdb.BucketUpdate) (*influxdb.Bucket, error) { + return &influxdb.Bucket{ + ID: 1, + OrgID: 10, + }, nil + }, + }, + }, + args: args{ + id: 1, + permissions: []influxdb.Permission{ + { + Action: "write", + Resource: influxdb.Resource{ + Type: influxdb.BucketsResourceType, + ID: influxdbtesting.IDPtr(1), + }, + }, + { + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.BucketsResourceType, + ID: influxdbtesting.IDPtr(1), + }, + }, + }, + }, + wants: wants{ + err: nil, + }, + }, + { + name: "unauthorized to update bucket", + fields: fields{ + BucketService: &mock.BucketService{ + FindBucketByIDFn: func(ctc context.Context, id influxdb.ID) (*influxdb.Bucket, error) { + return &influxdb.Bucket{ + ID: 1, + OrgID: 10, + }, nil + }, + UpdateBucketFn: func(ctx context.Context, id influxdb.ID, upd influxdb.BucketUpdate) (*influxdb.Bucket, error) { + return &influxdb.Bucket{ + ID: 1, + OrgID: 10, + }, nil + }, + }, + }, + args: args{ + id: 1, + permissions: []influxdb.Permission{ + { + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.BucketsResourceType, + ID: influxdbtesting.IDPtr(1), + }, + }, + }, + }, + wants: wants{ + err: &influxdb.Error{ + Msg: "write:orgs/000000000000000a/buckets/0000000000000001 is unauthorized", + Code: influxdb.EUnauthorized, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := tenant.NewAuthedBucketService(tt.fields.BucketService, nil) + + ctx := context.Background() + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) + + _, err := s.UpdateBucket(ctx, tt.args.id, influxdb.BucketUpdate{}) + influxdbtesting.ErrorsEqual(t, err, tt.wants.err) + }) + } +} + +func TestBucketService_DeleteBucket(t *testing.T) { + type fields struct { + BucketService influxdb.BucketService + } + type args struct { + id influxdb.ID + permissions []influxdb.Permission + } + type wants struct { + err error + } + + tests := []struct { + name string + fields fields + args args + wants wants + }{ + { + name: "authorized to delete bucket", + fields: fields{ + BucketService: &mock.BucketService{ + FindBucketByIDFn: func(ctc context.Context, id influxdb.ID) (*influxdb.Bucket, error) { + return &influxdb.Bucket{ + ID: 1, + OrgID: 10, + }, nil + }, + DeleteBucketFn: func(ctx context.Context, id influxdb.ID) error { + return nil + }, + }, + }, + args: args{ + id: 1, + permissions: []influxdb.Permission{ + { + Action: "write", + Resource: influxdb.Resource{ + Type: influxdb.BucketsResourceType, + ID: influxdbtesting.IDPtr(1), + }, + }, + { + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.BucketsResourceType, + ID: influxdbtesting.IDPtr(1), + }, + }, + }, + }, + wants: wants{ + err: nil, + }, + }, + { + name: "unauthorized to delete bucket", + fields: fields{ + BucketService: &mock.BucketService{ + FindBucketByIDFn: func(ctc context.Context, id influxdb.ID) (*influxdb.Bucket, error) { + return &influxdb.Bucket{ + ID: 1, + OrgID: 10, + }, nil + }, + DeleteBucketFn: func(ctx context.Context, id influxdb.ID) error { + return nil + }, + }, + }, + args: args{ + id: 1, + permissions: []influxdb.Permission{ + { + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.BucketsResourceType, + ID: influxdbtesting.IDPtr(1), + }, + }, + }, + }, + wants: wants{ + err: &influxdb.Error{ + Msg: "write:orgs/000000000000000a/buckets/0000000000000001 is unauthorized", + Code: influxdb.EUnauthorized, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := tenant.NewAuthedBucketService(tt.fields.BucketService, nil) + + ctx := context.Background() + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) + + err := s.DeleteBucket(ctx, tt.args.id) + influxdbtesting.ErrorsEqual(t, err, tt.wants.err) + }) + } +} + +func TestBucketService_CreateBucket(t *testing.T) { + type fields struct { + BucketService influxdb.BucketService + } + type args struct { + permission influxdb.Permission + orgID influxdb.ID + } + type wants struct { + err error + } + + tests := []struct { + name string + fields fields + args args + wants wants + }{ + { + name: "authorized to create bucket", + fields: fields{ + BucketService: &mock.BucketService{ + CreateBucketFn: func(ctx context.Context, b *influxdb.Bucket) error { + return nil + }, + }, + }, + args: args{ + orgID: 10, + permission: influxdb.Permission{ + Action: "write", + Resource: influxdb.Resource{ + Type: influxdb.BucketsResourceType, + OrgID: influxdbtesting.IDPtr(10), + }, + }, + }, + wants: wants{ + err: nil, + }, + }, + { + name: "unauthorized to create bucket", + fields: fields{ + BucketService: &mock.BucketService{ + CreateBucketFn: func(ctx context.Context, b *influxdb.Bucket) error { + return nil + }, + }, + }, + args: args{ + orgID: 10, + permission: influxdb.Permission{ + Action: "write", + Resource: influxdb.Resource{ + Type: influxdb.BucketsResourceType, + ID: influxdbtesting.IDPtr(1), + }, + }, + }, + wants: wants{ + err: &influxdb.Error{ + Msg: "write:orgs/000000000000000a/buckets is unauthorized", + Code: influxdb.EUnauthorized, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := tenant.NewAuthedBucketService(tt.fields.BucketService, nil) + + ctx := context.Background() + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) + + err := s.CreateBucket(ctx, &influxdb.Bucket{OrgID: tt.args.orgID}) + influxdbtesting.ErrorsEqual(t, err, tt.wants.err) + }) + } +} diff --git a/tenant/middleware_org_auth_test.go b/tenant/middleware_org_auth_test.go new file mode 100644 index 0000000000..faf4333ddb --- /dev/null +++ b/tenant/middleware_org_auth_test.go @@ -0,0 +1,557 @@ +package tenant_test + +import ( + "bytes" + "context" + "sort" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/influxdata/influxdb/v2" + influxdbcontext "github.com/influxdata/influxdb/v2/context" + "github.com/influxdata/influxdb/v2/mock" + "github.com/influxdata/influxdb/v2/tenant" + influxdbtesting "github.com/influxdata/influxdb/v2/testing" +) + +var orgCmpOptions = cmp.Options{ + cmp.Comparer(func(x, y []byte) bool { + return bytes.Equal(x, y) + }), + cmp.Transformer("Sort", func(in []*influxdb.Organization) []*influxdb.Organization { + out := append([]*influxdb.Organization(nil), in...) // Copy input to avoid mutating it + sort.Slice(out, func(i, j int) bool { + return out[i].ID.String() > out[j].ID.String() + }) + return out + }), +} + +func TestOrgService_FindOrganizationByID(t *testing.T) { + type fields struct { + OrgService influxdb.OrganizationService + } + type args struct { + permission influxdb.Permission + id influxdb.ID + } + type wants struct { + err error + } + + tests := []struct { + name string + fields fields + args args + wants wants + }{ + { + name: "authorized to access id", + fields: fields{ + OrgService: &mock.OrganizationService{ + FindOrganizationByIDF: func(ctx context.Context, id influxdb.ID) (*influxdb.Organization, error) { + return &influxdb.Organization{ + ID: id, + }, nil + }, + }, + }, + args: args{ + permission: influxdb.Permission{ + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.OrgsResourceType, + ID: influxdbtesting.IDPtr(1), + }, + }, + id: 1, + }, + wants: wants{ + err: nil, + }, + }, + { + name: "unauthorized to access id", + fields: fields{ + OrgService: &mock.OrganizationService{ + FindOrganizationByIDF: func(ctx context.Context, id influxdb.ID) (*influxdb.Organization, error) { + return &influxdb.Organization{ + ID: id, + }, nil + }, + }, + }, + args: args{ + permission: influxdb.Permission{ + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.OrgsResourceType, + ID: influxdbtesting.IDPtr(2), + }, + }, + id: 1, + }, + wants: wants{ + err: &influxdb.Error{ + Msg: "read:orgs/0000000000000001 is unauthorized", + Code: influxdb.EUnauthorized, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := tenant.NewAuthedOrgService(tt.fields.OrgService) + + ctx := context.Background() + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) + + _, err := s.FindOrganizationByID(ctx, tt.args.id) + influxdbtesting.ErrorsEqual(t, err, tt.wants.err) + }) + } +} + +func TestOrgService_FindOrganization(t *testing.T) { + type fields struct { + OrgService influxdb.OrganizationService + } + type args struct { + permission influxdb.Permission + } + type wants struct { + err error + } + + tests := []struct { + name string + fields fields + args args + wants wants + }{ + { + name: "authorized to access org", + fields: fields{ + OrgService: &mock.OrganizationService{ + FindOrganizationF: func(ctx context.Context, filter influxdb.OrganizationFilter) (*influxdb.Organization, error) { + return &influxdb.Organization{ + ID: 1, + }, nil + }, + }, + }, + args: args{ + permission: influxdb.Permission{ + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.OrgsResourceType, + ID: influxdbtesting.IDPtr(1), + }, + }, + }, + wants: wants{ + err: nil, + }, + }, + { + name: "unauthorized to access org", + fields: fields{ + OrgService: &mock.OrganizationService{ + FindOrganizationF: func(ctx context.Context, filter influxdb.OrganizationFilter) (*influxdb.Organization, error) { + return &influxdb.Organization{ + ID: 1, + }, nil + }, + }, + }, + args: args{ + permission: influxdb.Permission{ + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.OrgsResourceType, + ID: influxdbtesting.IDPtr(2), + }, + }, + }, + wants: wants{ + err: &influxdb.Error{ + Msg: "read:orgs/0000000000000001 is unauthorized", + Code: influxdb.EUnauthorized, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := tenant.NewAuthedOrgService(tt.fields.OrgService) + + ctx := context.Background() + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) + + _, err := s.FindOrganization(ctx, influxdb.OrganizationFilter{}) + influxdbtesting.ErrorsEqual(t, err, tt.wants.err) + }) + } +} + +func TestOrgService_FindOrganizations(t *testing.T) { + type fields struct { + OrgService influxdb.OrganizationService + } + type args struct { + permission influxdb.Permission + } + type wants struct { + err error + orgs []*influxdb.Organization + } + + tests := []struct { + name string + fields fields + args args + wants wants + }{ + { + name: "authorized to see all orgs", + fields: fields{ + OrgService: &mock.OrganizationService{ + FindOrganizationsF: func(ctx context.Context, filter influxdb.OrganizationFilter, opt ...influxdb.FindOptions) ([]*influxdb.Organization, int, error) { + return []*influxdb.Organization{ + { + ID: 1, + }, + { + ID: 2, + }, + { + ID: 3, + }, + }, 3, nil + }, + }, + }, + args: args{ + permission: influxdb.Permission{ + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.OrgsResourceType, + }, + }, + }, + wants: wants{ + orgs: []*influxdb.Organization{ + { + ID: 1, + }, + { + ID: 2, + }, + { + ID: 3, + }, + }, + }, + }, + { + name: "authorized to access a single org", + fields: fields{ + OrgService: &mock.OrganizationService{ + FindOrganizationsF: func(ctx context.Context, filter influxdb.OrganizationFilter, opt ...influxdb.FindOptions) ([]*influxdb.Organization, int, error) { + return []*influxdb.Organization{ + { + ID: 1, + }, + { + ID: 2, + }, + { + ID: 3, + }, + }, 3, nil + }, + }, + }, + args: args{ + permission: influxdb.Permission{ + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.OrgsResourceType, + ID: influxdbtesting.IDPtr(2), + }, + }, + }, + wants: wants{ + orgs: []*influxdb.Organization{ + { + ID: 2, + }, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := tenant.NewAuthedOrgService(tt.fields.OrgService) + + ctx := context.Background() + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) + + orgs, _, err := s.FindOrganizations(ctx, influxdb.OrganizationFilter{}) + influxdbtesting.ErrorsEqual(t, err, tt.wants.err) + + if diff := cmp.Diff(orgs, tt.wants.orgs, orgCmpOptions...); diff != "" { + t.Errorf("organizations are different -got/+want\ndiff %s", diff) + } + }) + } +} + +func TestOrgService_UpdateOrganization(t *testing.T) { + type fields struct { + OrgService influxdb.OrganizationService + } + type args struct { + id influxdb.ID + permission influxdb.Permission + } + type wants struct { + err error + } + + tests := []struct { + name string + fields fields + args args + wants wants + }{ + { + name: "authorized to update org", + fields: fields{ + OrgService: &mock.OrganizationService{ + UpdateOrganizationF: func(ctx context.Context, id influxdb.ID, upd influxdb.OrganizationUpdate) (*influxdb.Organization, error) { + return &influxdb.Organization{ + ID: 1, + }, nil + }, + }, + }, + args: args{ + id: 1, + permission: influxdb.Permission{ + Action: "write", + Resource: influxdb.Resource{ + Type: influxdb.OrgsResourceType, + ID: influxdbtesting.IDPtr(1), + }, + }, + }, + wants: wants{ + err: nil, + }, + }, + { + name: "unauthorized to update org", + fields: fields{ + OrgService: &mock.OrganizationService{ + UpdateOrganizationF: func(ctx context.Context, id influxdb.ID, upd influxdb.OrganizationUpdate) (*influxdb.Organization, error) { + return &influxdb.Organization{ + ID: 1, + }, nil + }, + }, + }, + args: args{ + id: 1, + permission: influxdb.Permission{ + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.OrgsResourceType, + ID: influxdbtesting.IDPtr(1), + }, + }, + }, + wants: wants{ + err: &influxdb.Error{ + Msg: "write:orgs/0000000000000001 is unauthorized", + Code: influxdb.EUnauthorized, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := tenant.NewAuthedOrgService(tt.fields.OrgService) + + ctx := context.Background() + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) + + _, err := s.UpdateOrganization(ctx, tt.args.id, influxdb.OrganizationUpdate{}) + influxdbtesting.ErrorsEqual(t, err, tt.wants.err) + }) + } +} + +func TestOrgService_DeleteOrganization(t *testing.T) { + type fields struct { + OrgService influxdb.OrganizationService + } + type args struct { + id influxdb.ID + permission influxdb.Permission + } + type wants struct { + err error + } + + tests := []struct { + name string + fields fields + args args + wants wants + }{ + { + name: "authorized to delete org", + fields: fields{ + OrgService: &mock.OrganizationService{ + DeleteOrganizationF: func(ctx context.Context, id influxdb.ID) error { + return nil + }, + }, + }, + args: args{ + id: 1, + permission: influxdb.Permission{ + Action: "write", + Resource: influxdb.Resource{ + Type: influxdb.OrgsResourceType, + ID: influxdbtesting.IDPtr(1), + }, + }, + }, + wants: wants{ + err: nil, + }, + }, + { + name: "unauthorized to delete org", + fields: fields{ + OrgService: &mock.OrganizationService{ + DeleteOrganizationF: func(ctx context.Context, id influxdb.ID) error { + return nil + }, + }, + }, + args: args{ + id: 1, + permission: influxdb.Permission{ + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.OrgsResourceType, + ID: influxdbtesting.IDPtr(1), + }, + }, + }, + wants: wants{ + err: &influxdb.Error{ + Msg: "write:orgs/0000000000000001 is unauthorized", + Code: influxdb.EUnauthorized, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := tenant.NewAuthedOrgService(tt.fields.OrgService) + + ctx := context.Background() + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) + + err := s.DeleteOrganization(ctx, tt.args.id) + influxdbtesting.ErrorsEqual(t, err, tt.wants.err) + }) + } +} + +func TestOrgService_CreateOrganization(t *testing.T) { + type fields struct { + OrgService influxdb.OrganizationService + } + type args struct { + permission influxdb.Permission + } + type wants struct { + err error + } + + tests := []struct { + name string + fields fields + args args + wants wants + }{ + { + name: "authorized to create org", + fields: fields{ + OrgService: &mock.OrganizationService{ + CreateOrganizationF: func(ctx context.Context, o *influxdb.Organization) error { + return nil + }, + }, + }, + args: args{ + permission: influxdb.Permission{ + Action: "write", + Resource: influxdb.Resource{ + Type: influxdb.OrgsResourceType, + }, + }, + }, + wants: wants{ + err: nil, + }, + }, + { + name: "unauthorized to create org", + fields: fields{ + OrgService: &mock.OrganizationService{ + CreateOrganizationF: func(ctx context.Context, o *influxdb.Organization) error { + return nil + }, + }, + }, + args: args{ + permission: influxdb.Permission{ + Action: "write", + Resource: influxdb.Resource{ + Type: influxdb.OrgsResourceType, + ID: influxdbtesting.IDPtr(1), + }, + }, + }, + wants: wants{ + err: &influxdb.Error{ + Msg: "write:orgs is unauthorized", + Code: influxdb.EUnauthorized, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := tenant.NewAuthedOrgService(tt.fields.OrgService) + + ctx := context.Background() + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) + + err := s.CreateOrganization(ctx, &influxdb.Organization{}) + influxdbtesting.ErrorsEqual(t, err, tt.wants.err) + }) + } +} diff --git a/tenant/middleware_urm_auth.go b/tenant/middleware_urm_auth.go new file mode 100644 index 0000000000..cd0807e2b1 --- /dev/null +++ b/tenant/middleware_urm_auth.go @@ -0,0 +1,90 @@ +package tenant + +import ( + "context" + + "github.com/influxdata/influxdb/v2" + "github.com/influxdata/influxdb/v2/authorizer" +) + +type AuthedURMService struct { + s influxdb.UserResourceMappingService + orgService influxdb.OrganizationService +} + +func NewAuthedURMService(orgSvc influxdb.OrganizationService, s influxdb.UserResourceMappingService) *AuthedURMService { + return &AuthedURMService{ + s: s, + orgService: orgSvc, + } +} + +func (s *AuthedURMService) FindUserResourceMappings(ctx context.Context, filter influxdb.UserResourceMappingFilter, opt ...influxdb.FindOptions) ([]*influxdb.UserResourceMapping, int, error) { + urms, _, err := s.s.FindUserResourceMappings(ctx, filter, opt...) + if err != nil { + return nil, 0, err + } + + authedUrms := urms[:0] + for _, urm := range urms { + orgID := orgIDFromContext(ctx) + if orgID != nil { + if _, _, err := authorizer.AuthorizeRead(ctx, urm.ResourceType, urm.ResourceID, *orgID); err != nil { + continue + } + } else { + if _, _, err := authorizer.AuthorizeReadResource(ctx, urm.ResourceType, urm.ResourceID); err != nil { + continue + } + } + authedUrms = append(authedUrms, urm) + } + + return authedUrms, len(authedUrms), nil +} + +func (s *AuthedURMService) CreateUserResourceMapping(ctx context.Context, m *influxdb.UserResourceMapping) error { + orgID := orgIDFromContext(ctx) + if orgID != nil { + if _, _, err := authorizer.AuthorizeWrite(ctx, m.ResourceType, m.ResourceID, *orgID); err != nil { + return err + } + } else { + if _, _, err := authorizer.AuthorizeWriteResource(ctx, m.ResourceType, m.ResourceID); err != nil { + return err + } + } + + return s.s.CreateUserResourceMapping(ctx, m) +} + +func (s *AuthedURMService) DeleteUserResourceMapping(ctx context.Context, resourceID influxdb.ID, userID influxdb.ID) error { + if !resourceID.Valid() || !userID.Valid() { + return ErrInvalidURMID + } + + f := influxdb.UserResourceMappingFilter{ResourceID: resourceID, UserID: userID} + urms, _, err := s.s.FindUserResourceMappings(ctx, f) + if err != nil { + return err + } + + // There should only be one because resourceID and userID are used to create the primary key for urms + for _, urm := range urms { + orgID := orgIDFromContext(ctx) + if orgID != nil { + if _, _, err := authorizer.AuthorizeWrite(ctx, urm.ResourceType, urm.ResourceID, *orgID); err != nil { + return err + } + } else { + if _, _, err := authorizer.AuthorizeWriteResource(ctx, urm.ResourceType, urm.ResourceID); err != nil { + return err + } + } + + if err := s.s.DeleteUserResourceMapping(ctx, urm.ResourceID, urm.UserID); err != nil { + return err + } + } + return nil +} diff --git a/tenant/middleware_urm_auth_test.go b/tenant/middleware_urm_auth_test.go new file mode 100644 index 0000000000..0ae374bacf --- /dev/null +++ b/tenant/middleware_urm_auth_test.go @@ -0,0 +1,334 @@ +package tenant + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/influxdata/influxdb/v2" + influxdbcontext "github.com/influxdata/influxdb/v2/context" + "github.com/influxdata/influxdb/v2/mock" + influxdbtesting "github.com/influxdata/influxdb/v2/testing" +) + +var idOne influxdb.ID = 1 +var idTwo influxdb.ID = 2 +var idThree influxdb.ID = 3 + +func TestURMService_FindUserResourceMappings(t *testing.T) { + type fields struct { + UserResourceMappingService influxdb.UserResourceMappingService + OrgService influxdb.OrganizationService + } + type args struct { + permissions []influxdb.Permission + } + type wants struct { + err error + urms []*influxdb.UserResourceMapping + } + + tests := []struct { + name string + fields fields + args args + wants wants + }{ + { + name: "authorized to see all users by org auth", + fields: fields{ + UserResourceMappingService: &mock.UserResourceMappingService{ + FindMappingsFn: func(ctx context.Context, filter influxdb.UserResourceMappingFilter) ([]*influxdb.UserResourceMapping, int, error) { + return []*influxdb.UserResourceMapping{ + { + ResourceID: 1, + ResourceType: influxdb.BucketsResourceType, + }, + { + ResourceID: 2, + ResourceType: influxdb.BucketsResourceType, + }, + { + ResourceID: 3, + ResourceType: influxdb.BucketsResourceType, + }, + }, 3, nil + }, + }, + }, + args: args{ + permissions: []influxdb.Permission{ + { + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.BucketsResourceType, + // ID: &idOne, + OrgID: influxdbtesting.IDPtr(10), + }, + }, + { + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.BucketsResourceType, + OrgID: influxdbtesting.IDPtr(10), + }, + }, + { + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.BucketsResourceType, + OrgID: influxdbtesting.IDPtr(10), + }, + }, + }, + }, + wants: wants{ + urms: []*influxdb.UserResourceMapping{ + { + ResourceID: 1, + ResourceType: influxdb.BucketsResourceType, + }, + { + ResourceID: 2, + ResourceType: influxdb.BucketsResourceType, + }, + { + ResourceID: 3, + ResourceType: influxdb.BucketsResourceType, + }, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewAuthedURMService(tt.fields.OrgService, tt.fields.UserResourceMappingService) + orgID := influxdbtesting.IDPtr(10) + ctx := context.WithValue(context.Background(), ctxOrgKey, *orgID) + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) + + urms, _, err := s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{}) + influxdbtesting.ErrorsEqual(t, err, tt.wants.err) + + if diff := cmp.Diff(urms, tt.wants.urms); diff != "" { + t.Errorf("urms are different -got/+want\ndiff %s", diff) + } + }) + } +} + +func TestURMService_FindUserResourceMappingsBucketAuth(t *testing.T) { + type fields struct { + UserResourceMappingService influxdb.UserResourceMappingService + OrgService influxdb.OrganizationService + } + type args struct { + permissions []influxdb.Permission + } + type wants struct { + err error + urms []*influxdb.UserResourceMapping + } + + tests := []struct { + name string + fields fields + args args + wants wants + }{ + { + name: "authorized to see all users by bucket auth", + fields: fields{ + UserResourceMappingService: &mock.UserResourceMappingService{ + FindMappingsFn: func(ctx context.Context, filter influxdb.UserResourceMappingFilter) ([]*influxdb.UserResourceMapping, int, error) { + return []*influxdb.UserResourceMapping{ + { + ResourceID: 1, + ResourceType: influxdb.BucketsResourceType, + }, + { + ResourceID: 2, + ResourceType: influxdb.BucketsResourceType, + }, + { + ResourceID: 3, + ResourceType: influxdb.BucketsResourceType, + }, + }, 3, nil + }, + }, + }, + args: args{ + permissions: []influxdb.Permission{ + { + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.BucketsResourceType, + ID: &idOne, + }, + }, + { + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.BucketsResourceType, + ID: &idTwo, + }, + }, + { + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.BucketsResourceType, + ID: &idThree, + }, + }, + }, + }, + wants: wants{ + urms: []*influxdb.UserResourceMapping{ + { + ResourceID: 1, + ResourceType: influxdb.BucketsResourceType, + }, + { + ResourceID: 2, + ResourceType: influxdb.BucketsResourceType, + }, + { + ResourceID: 3, + ResourceType: influxdb.BucketsResourceType, + }, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewAuthedURMService(tt.fields.OrgService, tt.fields.UserResourceMappingService) + + ctx := context.Background() + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, tt.args.permissions)) + + urms, _, err := s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{}) + influxdbtesting.ErrorsEqual(t, err, tt.wants.err) + + if diff := cmp.Diff(urms, tt.wants.urms); diff != "" { + t.Errorf("urms are different -got/+want\ndiff %s", diff) + } + }) + } +} + +func TestURMService_WriteUserResourceMapping(t *testing.T) { + type fields struct { + UserResourceMappingService influxdb.UserResourceMappingService + OrgService influxdb.OrganizationService + } + type args struct { + permission influxdb.Permission + } + type wants struct { + err error + } + + tests := []struct { + name string + fields fields + args args + wants wants + }{ + { + name: "authorized to write urm", + fields: fields{ + UserResourceMappingService: &mock.UserResourceMappingService{ + CreateMappingFn: func(ctx context.Context, m *influxdb.UserResourceMapping) error { + return nil + }, + DeleteMappingFn: func(ctx context.Context, rid, uid influxdb.ID) error { + return nil + }, + FindMappingsFn: func(ctx context.Context, filter influxdb.UserResourceMappingFilter) ([]*influxdb.UserResourceMapping, int, error) { + return []*influxdb.UserResourceMapping{ + { + ResourceID: 1, + ResourceType: influxdb.BucketsResourceType, + UserID: 100, + }, + }, 3, nil + }, + }, + }, + args: args{ + permission: influxdb.Permission{ + Action: "write", + Resource: influxdb.Resource{ + Type: influxdb.BucketsResourceType, + ID: &idOne, + OrgID: influxdbtesting.IDPtr(10), + }, + }, + }, + wants: wants{ + err: nil, + }, + }, + { + name: "unauthorized to write urm", + fields: fields{ + UserResourceMappingService: &mock.UserResourceMappingService{ + CreateMappingFn: func(ctx context.Context, m *influxdb.UserResourceMapping) error { + return nil + }, + DeleteMappingFn: func(ctx context.Context, rid, uid influxdb.ID) error { + return nil + }, + FindMappingsFn: func(ctx context.Context, filter influxdb.UserResourceMappingFilter) ([]*influxdb.UserResourceMapping, int, error) { + return []*influxdb.UserResourceMapping{ + { + ResourceID: 1, + ResourceType: influxdb.BucketsResourceType, + UserID: 100, + }, + }, 3, nil + }, + }, + }, + args: args{ + permission: influxdb.Permission{ + Action: "write", + Resource: influxdb.Resource{ + Type: influxdb.BucketsResourceType, + OrgID: influxdbtesting.IDPtr(11), + }, + }, + }, + wants: wants{ + err: &influxdb.Error{ + Msg: "write:buckets/0000000000000001 is unauthorized", + Code: influxdb.EUnauthorized, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewAuthedURMService(tt.fields.OrgService, tt.fields.UserResourceMappingService) + + ctx := context.Background() + ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) + + t.Run("create urm", func(t *testing.T) { + err := s.CreateUserResourceMapping(ctx, &influxdb.UserResourceMapping{ResourceType: influxdb.BucketsResourceType, ResourceID: 1}) + influxdbtesting.ErrorsEqual(t, err, tt.wants.err) + }) + + t.Run("delete urm", func(t *testing.T) { + err := s.DeleteUserResourceMapping(ctx, 1, 100) + influxdbtesting.ErrorsEqual(t, err, tt.wants.err) + }) + + }) + } +} diff --git a/tenant/middleware_user_auth.go b/tenant/middleware_user_auth.go index f78040ec08..a8d75c28ce 100644 --- a/tenant/middleware_user_auth.go +++ b/tenant/middleware_user_auth.go @@ -17,8 +17,8 @@ type AuthedUserService struct { s influxdb.UserService } -// NewUserService constructs an instance of an authorizing user serivce. -func NewUserService(s influxdb.UserService) *AuthedUserService { +// NewAuthedUserService constructs an instance of an authorizing user serivce. +func NewAuthedUserService(s influxdb.UserService) *AuthedUserService { return &AuthedUserService{ s: s, } @@ -78,3 +78,33 @@ func (s *AuthedUserService) DeleteUser(ctx context.Context, id influxdb.ID) erro } return s.s.DeleteUser(ctx, id) } + +// AuthedPasswordService is a new authorization middleware for a password service. +type AuthedPasswordService struct { + s influxdb.PasswordsService +} + +// NewAuthedPasswordService wraps an existing password service with auth middlware. +func NewAuthedPasswordService(svc influxdb.PasswordsService) *AuthedPasswordService { + return &AuthedPasswordService{s: svc} +} + +// SetPassword overrides the password of a known user. +func (s *AuthedPasswordService) SetPassword(ctx context.Context, userID influxdb.ID, password string) error { + if _, _, err := authorizer.AuthorizeWriteResource(ctx, influxdb.UsersResourceType, userID); err != nil { + return err + } + return s.s.SetPassword(ctx, userID, password) +} + +// ComparePassword checks if the password matches the password recorded. +// Passwords that do not match return errors. +func (s *AuthedPasswordService) ComparePassword(ctx context.Context, userID influxdb.ID, password string) error { + panic("not implemented") +} + +// CompareAndSetPassword checks the password and if they match +// updates to the new password. +func (s *AuthedPasswordService) CompareAndSetPassword(ctx context.Context, userID influxdb.ID, old string, new string) error { + panic("not implemented") +} diff --git a/tenant/middleware_user_auth_test.go b/tenant/middleware_user_auth_test.go new file mode 100644 index 0000000000..bacde80553 --- /dev/null +++ b/tenant/middleware_user_auth_test.go @@ -0,0 +1,648 @@ +package tenant_test + +import ( + "bytes" + "context" + "sort" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/influxdata/influxdb/v2" + "github.com/influxdata/influxdb/v2/authorizer" + icontext "github.com/influxdata/influxdb/v2/context" + "github.com/influxdata/influxdb/v2/mock" + "github.com/influxdata/influxdb/v2/tenant" + influxdbtesting "github.com/influxdata/influxdb/v2/testing" + "github.com/stretchr/testify/require" +) + +var userCmpOptions = cmp.Options{ + cmp.Comparer(func(x, y []byte) bool { + return bytes.Equal(x, y) + }), + cmp.Transformer("Sort", func(in []*influxdb.User) []*influxdb.User { + out := append([]*influxdb.User(nil), in...) // Copy input to avoid mutating it + sort.Slice(out, func(i, j int) bool { + return out[i].ID.String() > out[j].ID.String() + }) + return out + }), +} + +func TestUserService_FindUserByID(t *testing.T) { + type fields struct { + UserService influxdb.UserService + } + type args struct { + permission influxdb.Permission + id influxdb.ID + } + type wants struct { + err error + } + + tests := []struct { + name string + fields fields + args args + wants wants + }{ + { + name: "authorized to access id", + fields: fields{ + UserService: &mock.UserService{ + FindUserByIDFn: func(ctx context.Context, id influxdb.ID) (*influxdb.User, error) { + return &influxdb.User{ + ID: id, + }, nil + }, + }, + }, + args: args{ + permission: influxdb.Permission{ + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.UsersResourceType, + ID: influxdbtesting.IDPtr(1), + }, + }, + id: 1, + }, + wants: wants{ + err: nil, + }, + }, + { + name: "unauthorized to access id", + fields: fields{ + UserService: &mock.UserService{ + FindUserByIDFn: func(ctx context.Context, id influxdb.ID) (*influxdb.User, error) { + return &influxdb.User{ + ID: id, + }, nil + }, + }, + }, + args: args{ + permission: influxdb.Permission{ + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.UsersResourceType, + ID: influxdbtesting.IDPtr(2), + }, + }, + id: 1, + }, + wants: wants{ + err: &influxdb.Error{ + Msg: "read:users/0000000000000001 is unauthorized", + Code: influxdb.EUnauthorized, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := tenant.NewAuthedUserService(tt.fields.UserService) + + ctx := context.Background() + ctx = icontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) + + _, err := s.FindUserByID(ctx, tt.args.id) + influxdbtesting.ErrorsEqual(t, err, tt.wants.err) + }) + } +} + +func TestUserService_FindUser(t *testing.T) { + type fields struct { + UserService influxdb.UserService + } + type args struct { + permission influxdb.Permission + } + type wants struct { + err error + } + + tests := []struct { + name string + fields fields + args args + wants wants + }{ + { + name: "authorized to access user", + fields: fields{ + UserService: &mock.UserService{ + FindUserFn: func(ctx context.Context, filter influxdb.UserFilter) (*influxdb.User, error) { + return &influxdb.User{ + ID: 1, + }, nil + }, + }, + }, + args: args{ + permission: influxdb.Permission{ + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.UsersResourceType, + ID: influxdbtesting.IDPtr(1), + }, + }, + }, + wants: wants{ + err: nil, + }, + }, + { + name: "unauthorized to access user", + fields: fields{ + UserService: &mock.UserService{ + FindUserFn: func(ctx context.Context, filter influxdb.UserFilter) (*influxdb.User, error) { + return &influxdb.User{ + ID: 1, + }, nil + }, + }, + }, + args: args{ + permission: influxdb.Permission{ + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.UsersResourceType, + ID: influxdbtesting.IDPtr(2), + }, + }, + }, + wants: wants{ + err: &influxdb.Error{ + Msg: "read:users/0000000000000001 is unauthorized", + Code: influxdb.EUnauthorized, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := tenant.NewAuthedUserService(tt.fields.UserService) + + ctx := context.Background() + ctx = icontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) + + _, err := s.FindUser(ctx, influxdb.UserFilter{}) + influxdbtesting.ErrorsEqual(t, err, tt.wants.err) + }) + } +} + +func TestUserService_FindUsers(t *testing.T) { + type fields struct { + UserService influxdb.UserService + } + type args struct { + permission influxdb.Permission + } + type wants struct { + err error + users []*influxdb.User + } + + tests := []struct { + name string + fields fields + args args + wants wants + }{ + { + name: "authorized to see all users", + fields: fields{ + UserService: &mock.UserService{ + FindUsersFn: func(ctx context.Context, filter influxdb.UserFilter, opt ...influxdb.FindOptions) ([]*influxdb.User, int, error) { + return []*influxdb.User{ + { + ID: 1, + }, + { + ID: 2, + }, + { + ID: 3, + }, + }, 3, nil + }, + }, + }, + args: args{ + permission: influxdb.Permission{ + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.UsersResourceType, + }, + }, + }, + wants: wants{ + users: []*influxdb.User{ + { + ID: 1, + }, + { + ID: 2, + }, + { + ID: 3, + }, + }, + }, + }, + { + name: "authorized to access a single user", + fields: fields{ + UserService: &mock.UserService{ + FindUsersFn: func(ctx context.Context, filter influxdb.UserFilter, opt ...influxdb.FindOptions) ([]*influxdb.User, int, error) { + return []*influxdb.User{ + { + ID: 1, + }, + { + ID: 2, + }, + { + ID: 3, + }, + }, 3, nil + }, + }, + }, + args: args{ + permission: influxdb.Permission{ + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.UsersResourceType, + ID: influxdbtesting.IDPtr(2), + }, + }, + }, + wants: wants{ + users: []*influxdb.User{ + { + ID: 2, + }, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := tenant.NewAuthedUserService(tt.fields.UserService) + + ctx := context.Background() + ctx = icontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) + + users, _, err := s.FindUsers(ctx, influxdb.UserFilter{}) + influxdbtesting.ErrorsEqual(t, err, tt.wants.err) + + if diff := cmp.Diff(users, tt.wants.users, userCmpOptions...); diff != "" { + t.Errorf("users are different -got/+want\ndiff %s", diff) + } + }) + } +} + +func TestUserService_UpdateUser(t *testing.T) { + type fields struct { + UserService influxdb.UserService + } + type args struct { + id influxdb.ID + permission influxdb.Permission + } + type wants struct { + err error + } + + tests := []struct { + name string + fields fields + args args + wants wants + }{ + { + name: "authorized to update user", + fields: fields{ + UserService: &mock.UserService{ + UpdateUserFn: func(ctx context.Context, id influxdb.ID, upd influxdb.UserUpdate) (*influxdb.User, error) { + return &influxdb.User{ + ID: 1, + }, nil + }, + }, + }, + args: args{ + id: 1, + permission: influxdb.Permission{ + Action: "write", + Resource: influxdb.Resource{ + Type: influxdb.UsersResourceType, + ID: influxdbtesting.IDPtr(1), + }, + }, + }, + wants: wants{ + err: nil, + }, + }, + { + name: "unauthorized to update user", + fields: fields{ + UserService: &mock.UserService{ + UpdateUserFn: func(ctx context.Context, id influxdb.ID, upd influxdb.UserUpdate) (*influxdb.User, error) { + return &influxdb.User{ + ID: 1, + }, nil + }, + }, + }, + args: args{ + id: 1, + permission: influxdb.Permission{ + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.UsersResourceType, + ID: influxdbtesting.IDPtr(1), + }, + }, + }, + wants: wants{ + err: &influxdb.Error{ + Msg: "write:users/0000000000000001 is unauthorized", + Code: influxdb.EUnauthorized, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := tenant.NewAuthedUserService(tt.fields.UserService) + + ctx := context.Background() + ctx = icontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) + + _, err := s.UpdateUser(ctx, tt.args.id, influxdb.UserUpdate{}) + influxdbtesting.ErrorsEqual(t, err, tt.wants.err) + }) + } +} + +func TestUserService_DeleteUser(t *testing.T) { + type fields struct { + UserService influxdb.UserService + } + type args struct { + id influxdb.ID + permission influxdb.Permission + } + type wants struct { + err error + } + + tests := []struct { + name string + fields fields + args args + wants wants + }{ + { + name: "authorized to delete user", + fields: fields{ + UserService: &mock.UserService{ + DeleteUserFn: func(ctx context.Context, id influxdb.ID) error { + return nil + }, + }, + }, + args: args{ + id: 1, + permission: influxdb.Permission{ + Action: "write", + Resource: influxdb.Resource{ + Type: influxdb.UsersResourceType, + ID: influxdbtesting.IDPtr(1), + }, + }, + }, + wants: wants{ + err: nil, + }, + }, + { + name: "unauthorized to delete user", + fields: fields{ + UserService: &mock.UserService{ + DeleteUserFn: func(ctx context.Context, id influxdb.ID) error { + return nil + }, + }, + }, + args: args{ + id: 1, + permission: influxdb.Permission{ + Action: "read", + Resource: influxdb.Resource{ + Type: influxdb.UsersResourceType, + ID: influxdbtesting.IDPtr(1), + }, + }, + }, + wants: wants{ + err: &influxdb.Error{ + Msg: "write:users/0000000000000001 is unauthorized", + Code: influxdb.EUnauthorized, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := tenant.NewAuthedUserService(tt.fields.UserService) + + ctx := context.Background() + ctx = icontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) + + err := s.DeleteUser(ctx, tt.args.id) + influxdbtesting.ErrorsEqual(t, err, tt.wants.err) + }) + } +} + +func TestUserService_CreateUser(t *testing.T) { + type fields struct { + UserService influxdb.UserService + } + type args struct { + permission influxdb.Permission + } + type wants struct { + err error + } + + tests := []struct { + name string + fields fields + args args + wants wants + }{ + { + name: "authorized to create user", + fields: fields{ + UserService: &mock.UserService{ + CreateUserFn: func(ctx context.Context, o *influxdb.User) error { + return nil + }, + }, + }, + args: args{ + permission: influxdb.Permission{ + Action: "write", + Resource: influxdb.Resource{ + Type: influxdb.UsersResourceType, + }, + }, + }, + wants: wants{ + err: nil, + }, + }, + { + name: "unauthorized to create user", + fields: fields{ + UserService: &mock.UserService{ + CreateUserFn: func(ctx context.Context, o *influxdb.User) error { + return nil + }, + }, + }, + args: args{ + permission: influxdb.Permission{ + Action: "write", + Resource: influxdb.Resource{ + Type: influxdb.UsersResourceType, + ID: influxdbtesting.IDPtr(1), + }, + }, + }, + wants: wants{ + err: &influxdb.Error{ + Msg: "write:users is unauthorized", + Code: influxdb.EUnauthorized, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := tenant.NewAuthedUserService(tt.fields.UserService) + + ctx := context.Background() + ctx = icontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{tt.args.permission})) + + err := s.CreateUser(ctx, &influxdb.User{}) + influxdbtesting.ErrorsEqual(t, err, tt.wants.err) + }) + } +} + +func TestPasswordService(t *testing.T) { + t.Run("SetPassword", func(t *testing.T) { + t.Run("user with permissions should proceed", func(t *testing.T) { + userID := influxdb.ID(1) + + permission := influxdb.Permission{ + Action: influxdb.WriteAction, + Resource: influxdb.Resource{ + Type: influxdb.UsersResourceType, + ID: &userID, + }, + } + + fakeSVC := mock.NewPasswordsService() + fakeSVC.SetPasswordFn = func(_ context.Context, _ influxdb.ID, _ string) error { + return nil + } + s := tenant.NewAuthedPasswordService(fakeSVC) + + ctx := icontext.SetAuthorizer(context.Background(), mock.NewMockAuthorizer(false, []influxdb.Permission{permission})) + + err := s.SetPassword(ctx, 1, "password") + require.NoError(t, err) + }) + + t.Run("user without permissions should proceed", func(t *testing.T) { + goodUserID := influxdb.ID(1) + badUserID := influxdb.ID(3) + + tests := []struct { + name string + badPermission influxdb.Permission + }{ + { + name: "has no access", + }, + { + name: "has read only access on correct resource", + badPermission: influxdb.Permission{ + Action: influxdb.ReadAction, + Resource: influxdb.Resource{ + Type: influxdb.UsersResourceType, + ID: &goodUserID, + }, + }, + }, + { + name: "has write access on incorrect resource", + badPermission: influxdb.Permission{ + Action: influxdb.WriteAction, + Resource: influxdb.Resource{ + Type: influxdb.OrgsResourceType, + ID: &goodUserID, + }, + }, + }, + { + name: "user accessing user that is not self", + badPermission: influxdb.Permission{ + Action: influxdb.WriteAction, + Resource: influxdb.Resource{ + Type: influxdb.UsersResourceType, + ID: &badUserID, + }, + }, + }, + } + + for _, tt := range tests { + fn := func(t *testing.T) { + fakeSVC := &mock.PasswordsService{ + SetPasswordFn: func(_ context.Context, _ influxdb.ID, _ string) error { + return nil + }, + } + s := authorizer.NewPasswordService(fakeSVC) + + ctx := icontext.SetAuthorizer(context.Background(), mock.NewMockAuthorizer(false, []influxdb.Permission{tt.badPermission})) + + err := s.SetPassword(ctx, goodUserID, "password") + require.Error(t, err) + } + + t.Run(tt.name, fn) + } + }) + }) +} diff --git a/tenant/service_user.go b/tenant/service_user.go index 2e8aaf8e74..eb3699736d 100644 --- a/tenant/service_user.go +++ b/tenant/service_user.go @@ -136,7 +136,7 @@ func (s *Service) SetPassword(ctx context.Context, userID influxdb.ID, password if len(password) < 8 { return EShortPassword } - passHash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) + passHash, err := encryptPassword(password) if err != nil { return err } @@ -146,7 +146,7 @@ func (s *Service) SetPassword(ctx context.Context, userID influxdb.ID, password if err != nil { return EIncorrectUser } - return s.store.SetPassword(ctx, tx, userID, string(passHash)) + return s.store.SetPassword(ctx, tx, userID, passHash) }) } diff --git a/testing/tenant.go b/testing/tenant.go index 4b91d46d9d..b55205f4e8 100644 --- a/testing/tenant.go +++ b/testing/tenant.go @@ -443,6 +443,7 @@ func Create(t *testing.T, init func(*testing.T, TenantFields) (influxdb.TenantSe if err != nil { t.Fatal(err) } + sort.Sort(urmByResourceID(urms)) if diff := cmp.Diff(want, urms); diff != "" { t.Errorf("unexpected urms -want/+got:\n\t%s", diff)