From 3795aeb0872570377126887bb78f1c6321d0e429 Mon Sep 17 00:00:00 2001 From: Eli K Miller Date: Tue, 23 Jan 2024 13:51:12 -0600 Subject: [PATCH 1/8] feat: introduce new role "Power User" --- cmd/api/src/auth/role.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/cmd/api/src/auth/role.go b/cmd/api/src/auth/role.go index 7a56745ef1..5836c9434e 100644 --- a/cmd/api/src/auth/role.go +++ b/cmd/api/src/auth/role.go @@ -26,6 +26,7 @@ const ( RoleUploadOnly = "Upload-Only" RoleReadOnly = "Read-Only" RoleUser = "User" + RolePowerUser = "Power User" RoleAdministrator = "Administrator" ) @@ -98,6 +99,27 @@ func Roles() map[string]RoleTemplate { permissions.ClientsRead, }, }, + RolePowerUser: { + Name: RolePowerUser, + Description: "", + Permissions: model.Permissions{ + permissions.GraphDBWrite, + permissions.GraphDBRead, + permissions.AppReadApplicationConfiguration, + permissions.AppWriteApplicationConfiguration, + permissions.CollectionManageJobs, + permissions.ClientsManage, + permissions.ClientsTasking, + permissions.AuthCreateToken, + permissions.AuthManageSelf, + permissions.AuthManageApplicationConfigurations, + permissions.APsGenerateReport, + permissions.APsManageAPs, + permissions.SavedQueriesRead, + permissions.SavedQueriesWrite, + permissions.ClientsRead, + }, + }, RoleAdministrator: { Name: RoleAdministrator, Description: "Can manage users, clients, and application configuration", From 1c0289f4021833f7fda4be6a01aed83c2c81eba9 Mon Sep 17 00:00:00 2001 From: Eli K Miller Date: Tue, 23 Jan 2024 13:58:53 -0600 Subject: [PATCH 2/8] chore: add "Power User" role description. Revoke the "AuthManageApplicationConfigurations" permission from "Power User" as it is not in use. --- cmd/api/src/auth/role.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmd/api/src/auth/role.go b/cmd/api/src/auth/role.go index 5836c9434e..066b0017ca 100644 --- a/cmd/api/src/auth/role.go +++ b/cmd/api/src/auth/role.go @@ -101,7 +101,7 @@ func Roles() map[string]RoleTemplate { }, RolePowerUser: { Name: RolePowerUser, - Description: "", + Description: "Can upload data, manage clients, and perform any action a User can", Permissions: model.Permissions{ permissions.GraphDBWrite, permissions.GraphDBRead, @@ -112,7 +112,6 @@ func Roles() map[string]RoleTemplate { permissions.ClientsTasking, permissions.AuthCreateToken, permissions.AuthManageSelf, - permissions.AuthManageApplicationConfigurations, permissions.APsGenerateReport, permissions.APsManageAPs, permissions.SavedQueriesRead, From 57f8c93f6b067c07e8c395a7d63a81d138ea1d03 Mon Sep 17 00:00:00 2001 From: Mistah J <26472282+mistahj67@users.noreply.github.com> Date: Thu, 25 Jan 2024 17:16:05 -0800 Subject: [PATCH 3/8] add tests for "Power User" auth --- cmd/api/src/api/v2/apiclient/auth.go | 2 +- .../api/v2/cypher_search_integration_test.go | 10 +- cmd/api/src/auth/role_test.go | 150 ++++++++++++++++++ cmd/api/src/test/lab/fixtures/apiclient.go | 61 ++++++- 4 files changed, 215 insertions(+), 8 deletions(-) create mode 100644 cmd/api/src/auth/role_test.go diff --git a/cmd/api/src/api/v2/apiclient/auth.go b/cmd/api/src/api/v2/apiclient/auth.go index c67492884b..5594177a83 100644 --- a/cmd/api/src/api/v2/apiclient/auth.go +++ b/cmd/api/src/api/v2/apiclient/auth.go @@ -380,7 +380,7 @@ func (s Client) GetPermission(id int32) (model.Permission, error) { func (s Client) ListPermissions() (v2.ListPermissionsResponse, error) { var permissions v2.ListPermissionsResponse - if response, err := s.Request(http.MethodGet, "api/v2/auth/permissions", nil, nil); err != nil { + if response, err := s.Request(http.MethodGet, "api/v2/permissions", nil, nil); err != nil { return permissions, err } else { defer response.Body.Close() diff --git a/cmd/api/src/api/v2/cypher_search_integration_test.go b/cmd/api/src/api/v2/cypher_search_integration_test.go index 31367aadbd..5e2906c82b 100644 --- a/cmd/api/src/api/v2/cypher_search_integration_test.go +++ b/cmd/api/src/api/v2/cypher_search_integration_test.go @@ -33,21 +33,21 @@ import ( func Test_CypherSearch(t *testing.T) { var ( - harness = harnesses.NewIntegrationTestHarness(fixtures.BHApiClientFixture) + harness = harnesses.NewIntegrationTestHarness(fixtures.BHAdminApiClientFixture) ) lab.Pack(harness, fixtures.BasicComputerFixture) lab.NewSpec(t, harness).Run( lab.TestCase("errors on empty input", func(assert *require.Assertions, harness *lab.Harness) { - apiClient, ok := lab.Unpack(harness, fixtures.BHApiClientFixture) + apiClient, ok := lab.Unpack(harness, fixtures.BHAdminApiClientFixture) assert.True(ok) _, err := apiClient.CypherSearch(v2.CypherSearch{}) assert.ErrorContains(err, frontend.ErrInvalidInput.Error()) }), lab.TestCase("errors on syntax mistake", func(assert *require.Assertions, harness *lab.Harness) { - apiClient, ok := lab.Unpack(harness, fixtures.BHApiClientFixture) + apiClient, ok := lab.Unpack(harness, fixtures.BHAdminApiClientFixture) assert.True(ok) _, err := apiClient.CypherSearch(v2.CypherSearch{ @@ -56,7 +56,7 @@ func Test_CypherSearch(t *testing.T) { assert.ErrorContains(err, "extraneous input") }), lab.TestCase("errors on queries that are not supported", func(assert *require.Assertions, harness *lab.Harness) { - apiClient, ok := lab.Unpack(harness, fixtures.BHApiClientFixture) + apiClient, ok := lab.Unpack(harness, fixtures.BHAdminApiClientFixture) assert.True(ok) queryWithUpdateClause := "match (b) where b.name = 'test' remove b.prop return b" @@ -66,7 +66,7 @@ func Test_CypherSearch(t *testing.T) { assert.ErrorContains(err, frontend.ErrUpdateClauseNotSupported.Error()) }), lab.TestCase("succesfully runs cypher query", func(assert *require.Assertions, harness *lab.Harness) { - apiClient, ok := lab.Unpack(harness, fixtures.BHApiClientFixture) + apiClient, ok := lab.Unpack(harness, fixtures.BHAdminApiClientFixture) assert.True(ok) graphResponse, err := apiClient.CypherSearch(v2.CypherSearch{ diff --git a/cmd/api/src/auth/role_test.go b/cmd/api/src/auth/role_test.go new file mode 100644 index 0000000000..70779e02ce --- /dev/null +++ b/cmd/api/src/auth/role_test.go @@ -0,0 +1,150 @@ +// Copyright 2023 Specter Ops, Inc. +// +// Licensed under the Apache License, Version 2.0 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +//go:build integration +// +build integration + +package auth_test + +import ( + "encoding/json" + "github.com/gofrs/uuid" + "github.com/specterops/bloodhound/lab" + "github.com/specterops/bloodhound/src/api" + v2 "github.com/specterops/bloodhound/src/api/v2" + "github.com/specterops/bloodhound/src/auth" + "github.com/specterops/bloodhound/src/model/appcfg" + "github.com/specterops/bloodhound/src/test/lab/fixtures" + "github.com/stretchr/testify/require" + "net/http" + "testing" + "time" +) + +func TestRole_PowerUser(t *testing.T) { + + harness := lab.NewHarness() + lab.Pack(harness, fixtures.BHAdminApiClientFixture) + powerUserClientFixture := fixtures.NewUserApiClientFixture(fixtures.BHAdminApiClientFixture, auth.RolePowerUser) + lab.Pack(harness, powerUserClientFixture) + + lab.NewSpec(t, harness).Run( + lab.TestCase("SHOULD be able to access AppReadApplicationConfiguration endpoints", func(assert *require.Assertions, harness *lab.Harness) { + powerUserClient, ok := lab.Unpack(harness, powerUserClientFixture) + assert.True(ok) + + _, err := powerUserClient.GetAppConfigs() + require.Nil(t, err) + }), + + lab.TestCase("SHOULD be able to access AppWriteApplicationConfiguration endpoints", func(assert *require.Assertions, harness *lab.Harness) { + powerUserClient, ok := lab.Unpack(harness, powerUserClientFixture) + assert.True(ok) + + updatedPasswordExpirationWindowParameter := v2.AppConfigUpdateRequest{ + Key: appcfg.PasswordExpirationWindow, + Value: map[string]any{ + "duration": "P30D", + }, + } + _, err := powerUserClient.PutAppConfig(updatedPasswordExpirationWindowParameter) + require.Nil(t, err) + }), + + lab.TestCase("SHOULD be able to access AuthCreateToken endpoints", func(assert *require.Assertions, harness *lab.Harness) { + powerUserClient, ok := lab.Unpack(harness, powerUserClientFixture) + assert.True(ok) + + randomUserUuid, err := uuid.NewV4() + require.Nil(t, err) + + _, err = powerUserClient.ListUserTokens(randomUserUuid) + require.Nil(t, err) + }), + + lab.TestCase("SHOULD NOT be able to access AuthManageProviders endpoints", func(assert *require.Assertions, harness *lab.Harness) { + powerUserClient, ok := lab.Unpack(harness, powerUserClientFixture) + assert.True(ok) + + _, err := powerUserClient.ListSAMLIdentityProviders() + var errByte []byte + errByte, err = json.Marshal(err) + require.Nil(t, err) + + errWrapper := api.ErrorWrapper{} + err = json.Unmarshal(errByte, &errWrapper) + require.Nil(t, err) + require.Equal(t, errWrapper.HTTPStatus, http.StatusForbidden) + }), + + lab.TestCase("SHOULD be able to access AuthManageSelf endpoints", func(assert *require.Assertions, harness *lab.Harness) { + powerUserClient, ok := lab.Unpack(harness, powerUserClientFixture) + assert.True(ok) + + _, err := powerUserClient.ListPermissions() + require.Nil(t, err) + }), + + lab.TestCase("SHOULD NOT be able to access AuthManageUsers endpoints", func(assert *require.Assertions, harness *lab.Harness) { + powerUserClient, ok := lab.Unpack(harness, powerUserClientFixture) + assert.True(ok) + + _, err := powerUserClient.ListAuditLogs(time.Now(), time.Now(), 0, 0) + require.NotNil(t, err) + + var errByte []byte + errByte, err = json.Marshal(err) + require.Nil(t, err) + + errWrapper := api.ErrorWrapper{} + err = json.Unmarshal(errByte, &errWrapper) + require.Nil(t, err) + require.Equal(t, errWrapper.HTTPStatus, http.StatusForbidden) + }), + + lab.TestCase("SHOULD be able to access GraphDbWrite endpoints", func(assert *require.Assertions, harness *lab.Harness) { + powerUserClient, ok := lab.Unpack(harness, powerUserClientFixture) + assert.True(ok) + + _, err := powerUserClient.CreateFileUploadTask() + require.Nil(t, err) + }), + + lab.TestCase("SHOULD be able to access GraphDbRead endpoints", func(assert *require.Assertions, harness *lab.Harness) { + powerUserClient, ok := lab.Unpack(harness, powerUserClientFixture) + assert.True(ok) + + _, err := powerUserClient.ListAssetGroups() + require.Nil(t, err) + }), + + lab.TestCase("SHOULD be able to access SavedQueriesRead endpoints", func(assert *require.Assertions, harness *lab.Harness) { + powerUserClient, ok := lab.Unpack(harness, powerUserClientFixture) + assert.True(ok) + + _, err := powerUserClient.ListPermissions() + require.Nil(t, err) + }), + + lab.TestCase("SHOULD be able to access SavedQueriesWrite endpoints", func(assert *require.Assertions, harness *lab.Harness) { + powerUserClient, ok := lab.Unpack(harness, powerUserClientFixture) + assert.True(ok) + + _, err := powerUserClient.ListPermissions() + require.Nil(t, err) + }), + ) +} diff --git a/cmd/api/src/test/lab/fixtures/apiclient.go b/cmd/api/src/test/lab/fixtures/apiclient.go index a75ac3a09b..29b6154295 100644 --- a/cmd/api/src/test/lab/fixtures/apiclient.go +++ b/cmd/api/src/test/lab/fixtures/apiclient.go @@ -18,6 +18,7 @@ package fixtures import ( "fmt" + "github.com/specterops/bloodhound/src/config" "log" "github.com/specterops/bloodhound/lab" @@ -25,9 +26,9 @@ import ( "github.com/specterops/bloodhound/src/api/v2/integration" ) -var BHApiClientFixture = NewApiClientFixture(BHApiFixture) +var BHAdminApiClientFixture = NewAdminApiClientFixture(BHApiFixture) -func NewApiClientFixture(apiFixture *lab.Fixture[bool]) *lab.Fixture[apiclient.Client] { +func NewAdminApiClientFixture(apiFixture *lab.Fixture[bool]) *lab.Fixture[apiclient.Client] { fixture := lab.NewFixture(func(harness *lab.Harness) (apiclient.Client, error) { if config, ok := lab.Unpack(harness, ConfigFixture); !ok { return apiclient.Client{}, fmt.Errorf("unable to unpack ConfigFixture") @@ -59,3 +60,59 @@ func NewApiClientFixture(apiFixture *lab.Fixture[bool]) *lab.Fixture[apiclient.C } return fixture } + +func NewUserApiClientFixture(adminApiFixture *lab.Fixture[apiclient.Client], roleNames ...string) *lab.Fixture[apiclient.Client] { + fixture := lab.NewFixture(func(harness *lab.Harness) (apiclient.Client, error) { + if configFixture, ok := lab.Unpack(harness, ConfigFixture); !ok { + return apiclient.Client{}, fmt.Errorf("unable to unpack ConfigFixture") + } else if adminClient, ok := lab.Unpack(harness, BHAdminApiClientFixture); !ok { + return apiclient.Client{}, fmt.Errorf("unable to unpack BHAdminApiClientFixture") + } else if username, err := config.GenerateSecureRandomString(7); err != nil { + return apiclient.Client{}, fmt.Errorf("unable to generate random username") + } else if secret, err := config.GenerateRandomBase64String(32); err != nil { + return apiclient.Client{}, fmt.Errorf("unable to generate secret") + } else if roles, err := adminClient.ListRoles(); err != nil { + return apiclient.Client{}, fmt.Errorf("unable to get roles") + } else { + var roleIds []int32 + for _, r := range roleNames { + if foundRole, found := roles.Roles.FindByName(r); !found { + return apiclient.Client{}, fmt.Errorf("unable to find role") + } else { + roleIds = append(roleIds, foundRole.ID) + } + } + + // Create user in database + if user, err := adminClient.CreateUser(username, "", roleIds); err != nil { + return apiclient.Client{}, fmt.Errorf("failed to create user in db") + } else { + if err := adminClient.SetUserSecret(user.ID, secret, false); err != nil { + return apiclient.Client{}, fmt.Errorf("failed resetting expired user password: %w", err) + } + } + // Get api client for user + client, err := apiclient.NewClient(configFixture.RootURL.String()) + if err != nil { + return apiclient.Client{}, fmt.Errorf("unable to initialize api client: %w", err) + } + + credentials := &apiclient.SecretCredentialsHandler{ + Username: username, + Secret: secret, + } + credentials.Client = client + client.Credentials = credentials + + if _, err := client.GetSelf(); err != nil { + return apiclient.Client{}, fmt.Errorf("failed looking up user details: %w", err) + } + + return client, nil + } + }, nil) + if err := lab.SetDependency(fixture, adminApiFixture); err != nil { + log.Fatalln(err) + } + return fixture +} From 9dda6d748693509f4c4ad3ccb5a0d92b22b5db51 Mon Sep 17 00:00:00 2001 From: Mistah J <26472282+mistahj67@users.noreply.github.com> Date: Mon, 29 Jan 2024 10:09:42 -0700 Subject: [PATCH 4/8] alphabetize permissions --- cmd/api/src/auth/permission.go | 74 +++++++++++++++++----------------- cmd/api/src/auth/role.go | 32 +++++++-------- 2 files changed, 52 insertions(+), 54 deletions(-) diff --git a/cmd/api/src/auth/permission.go b/cmd/api/src/auth/permission.go index af2dcb78d5..85119cd7e8 100644 --- a/cmd/api/src/auth/permission.go +++ b/cmd/api/src/auth/permission.go @@ -21,81 +21,79 @@ import ( ) type PermissionSet struct { - GraphDBRead model.Permission - GraphDBWrite model.Permission - AppReadApplicationConfiguration model.Permission AppWriteApplicationConfiguration model.Permission - CollectionManageJobs model.Permission - - ClientsManage model.Permission - ClientsTasking model.Permission + APsGenerateReport model.Permission + APsManageAPs model.Permission + AuthAcceptEULA model.Permission AuthCreateToken model.Permission + AuthManageApplicationConfigurations model.Permission + AuthManageProviders model.Permission AuthManageSelf model.Permission - AuthAcceptEULA model.Permission AuthManageUsers model.Permission - AuthManageProviders model.Permission - AuthManageApplicationConfigurations model.Permission - APsGenerateReport model.Permission - APsManageAPs model.Permission + ClientsManage model.Permission + ClientsRead model.Permission + ClientsTasking model.Permission + + CollectionManageJobs model.Permission + + GraphDBRead model.Permission + GraphDBWrite model.Permission SavedQueriesRead model.Permission SavedQueriesWrite model.Permission - - ClientsRead model.Permission } func (s PermissionSet) All() model.Permissions { return model.Permissions{ - s.GraphDBWrite, - s.GraphDBRead, s.AppReadApplicationConfiguration, s.AppWriteApplicationConfiguration, - s.CollectionManageJobs, - s.ClientsManage, - s.ClientsTasking, + s.APsGenerateReport, + s.APsManageAPs, s.AuthCreateToken, - s.AuthManageUsers, + s.AuthManageApplicationConfigurations, s.AuthManageProviders, s.AuthManageSelf, - s.AuthManageApplicationConfigurations, - s.APsGenerateReport, - s.APsManageAPs, + s.AuthManageUsers, + s.ClientsManage, + s.ClientsRead, + s.ClientsTasking, + s.CollectionManageJobs, + s.GraphDBRead, + s.GraphDBWrite, s.SavedQueriesRead, s.SavedQueriesWrite, - s.ClientsRead, } } func Permissions() PermissionSet { return PermissionSet{ - GraphDBRead: model.NewPermission("graphdb", "Read"), - GraphDBWrite: model.NewPermission("graphdb", "Write"), - AppReadApplicationConfiguration: model.NewPermission("app", "ReadAppConfig"), AppWriteApplicationConfiguration: model.NewPermission("app", "WriteAppConfig"), - CollectionManageJobs: model.NewPermission("collection", "ManageJobs"), - - ClientsManage: model.NewPermission("clients", "Manage"), - ClientsTasking: model.NewPermission("clients", "Tasking"), + APsGenerateReport: model.NewPermission("risks", "GenerateReport"), + APsManageAPs: model.NewPermission("risks", "ManageRisks"), - AuthCreateToken: model.NewPermission("auth", "CreateToken"), - AuthManageSelf: model.NewPermission("auth", "ManageSelf"), AuthAcceptEULA: model.NewPermission("auth", "AcceptEULA"), + AuthCreateToken: model.NewPermission("auth", "CreateToken"), + AuthManageApplicationConfigurations: model.NewPermission("auth", "ManageAppConfig"), AuthManageProviders: model.NewPermission("auth", "ManageProviders"), + AuthManageSelf: model.NewPermission("auth", "ManageSelf"), AuthManageUsers: model.NewPermission("auth", "ManageUsers"), - AuthManageApplicationConfigurations: model.NewPermission("auth", "ManageAppConfig"), - APsGenerateReport: model.NewPermission("risks", "GenerateReport"), - APsManageAPs: model.NewPermission("risks", "ManageRisks"), + ClientsManage: model.NewPermission("clients", "Manage"), + ClientsRead: model.NewPermission("clients", "Read"), + ClientsTasking: model.NewPermission("clients", "Tasking"), + + CollectionManageJobs: model.NewPermission("collection", "ManageJobs"), + + GraphDBRead: model.NewPermission("graphdb", "Read"), + GraphDBWrite: model.NewPermission("graphdb", "Write"), SavedQueriesRead: model.NewPermission("saved_queries", "Read"), SavedQueriesWrite: model.NewPermission("saved_queries", "Write"), - - ClientsRead: model.NewPermission("clients", "Read"), } } diff --git a/cmd/api/src/auth/role.go b/cmd/api/src/auth/role.go index 066b0017ca..69d63a610c 100644 --- a/cmd/api/src/auth/role.go +++ b/cmd/api/src/auth/role.go @@ -71,52 +71,52 @@ func Roles() map[string]RoleTemplate { Name: RoleReadOnly, Description: "Used for integrations", Permissions: model.Permissions{ - permissions.GraphDBRead, - permissions.AuthManageSelf, - permissions.APsGenerateReport, permissions.AppReadApplicationConfiguration, + permissions.APsGenerateReport, + permissions.AuthManageSelf, + permissions.GraphDBRead, }, }, RoleUploadOnly: { Name: RoleUploadOnly, Description: "Used for data collection clients, can post data but cannot read data", Permissions: model.Permissions{ - permissions.GraphDBWrite, permissions.ClientsTasking, + permissions.GraphDBWrite, }, }, RoleUser: { Name: RoleUser, Description: "Can read data, modify asset group memberships", Permissions: model.Permissions{ - permissions.GraphDBRead, + permissions.AppReadApplicationConfiguration, + permissions.APsGenerateReport, permissions.AuthCreateToken, permissions.AuthManageSelf, - permissions.APsGenerateReport, - permissions.AppReadApplicationConfiguration, + permissions.ClientsRead, + permissions.GraphDBRead, permissions.SavedQueriesRead, permissions.SavedQueriesWrite, - permissions.ClientsRead, }, }, RolePowerUser: { Name: RolePowerUser, Description: "Can upload data, manage clients, and perform any action a User can", Permissions: model.Permissions{ - permissions.GraphDBWrite, - permissions.GraphDBRead, permissions.AppReadApplicationConfiguration, permissions.AppWriteApplicationConfiguration, - permissions.CollectionManageJobs, - permissions.ClientsManage, - permissions.ClientsTasking, - permissions.AuthCreateToken, - permissions.AuthManageSelf, permissions.APsGenerateReport, permissions.APsManageAPs, + permissions.AuthCreateToken, + permissions.AuthManageSelf, + permissions.ClientsManage, + permissions.ClientsRead, + permissions.ClientsTasking, + permissions.CollectionManageJobs, + permissions.GraphDBWrite, + permissions.GraphDBRead, permissions.SavedQueriesRead, permissions.SavedQueriesWrite, - permissions.ClientsRead, }, }, RoleAdministrator: { From 9b15040ef3905a136a67d4f659d4ebea943286c8 Mon Sep 17 00:00:00 2001 From: Mistah J <26472282+mistahj67@users.noreply.github.com> Date: Mon, 29 Jan 2024 13:06:38 -0700 Subject: [PATCH 5/8] update & abstract role tests to other roles --- cmd/api/src/api/v2/apiclient/savedqueries.go | 43 ++++ cmd/api/src/auth/role_test.go | 199 +++++++++++++------ 2 files changed, 184 insertions(+), 58 deletions(-) create mode 100644 cmd/api/src/api/v2/apiclient/savedqueries.go diff --git a/cmd/api/src/api/v2/apiclient/savedqueries.go b/cmd/api/src/api/v2/apiclient/savedqueries.go new file mode 100644 index 0000000000..d69ee29c8e --- /dev/null +++ b/cmd/api/src/api/v2/apiclient/savedqueries.go @@ -0,0 +1,43 @@ +package apiclient + +import ( + "github.com/specterops/bloodhound/src/api" + v2 "github.com/specterops/bloodhound/src/api/v2" + "github.com/specterops/bloodhound/src/model" + "net/http" +) + +func (s Client) ListSavedQueries() (model.SavedQueries, error) { + var queries model.SavedQueries + if response, err := s.Request(http.MethodGet, "api/v2/saved-queries", nil, nil); err != nil { + return queries, err + } else { + defer response.Body.Close() + + if api.IsErrorResponse(response) { + return queries, ReadAPIError(response) + } + + return queries, api.ReadAPIV2ResponsePayload(&queries, response) + } +} + +func (s Client) CreateSavedQuery() (model.SavedQuery, error) { + var query model.SavedQuery + payload := v2.CreateSavedQueryRequest{ + Query: "Match(q:Question {life: 1, universe: 1, everything: 1}) return q", + Name: "AnswerToLifeUniverseEverything", + } + + if response, err := s.Request(http.MethodPost, "api/v2/saved-queries", nil, payload); err != nil { + return query, err + } else { + defer response.Body.Close() + + if api.IsErrorResponse(response) { + return query, ReadAPIError(response) + } + + return query, api.ReadAPIV2ResponsePayload(&query, response) + } +} diff --git a/cmd/api/src/auth/role_test.go b/cmd/api/src/auth/role_test.go index 70779e02ce..8bcacf7f73 100644 --- a/cmd/api/src/auth/role_test.go +++ b/cmd/api/src/auth/role_test.go @@ -21,11 +21,13 @@ package auth_test import ( "encoding/json" + "fmt" "github.com/gofrs/uuid" "github.com/specterops/bloodhound/lab" "github.com/specterops/bloodhound/src/api" v2 "github.com/specterops/bloodhound/src/api/v2" "github.com/specterops/bloodhound/src/auth" + "github.com/specterops/bloodhound/src/model" "github.com/specterops/bloodhound/src/model/appcfg" "github.com/specterops/bloodhound/src/test/lab/fixtures" "github.com/stretchr/testify/require" @@ -34,24 +36,48 @@ import ( "time" ) -func TestRole_PowerUser(t *testing.T) { +func testCondition(role auth.RoleTemplate, permission model.Permission) string { + if role.Permissions.Has(permission) { + return "SHOULD" + } + return "SHOULD NOT" +} + +func requireForbidden(t *testing.T, err error) { + var errByte []byte + errByte, err = json.Marshal(err) + require.Nil(t, err) + + errWrapper := api.ErrorWrapper{} + err = json.Unmarshal(errByte, &errWrapper) + require.Nilf(t, err, "Failed to unmarshal error %v", string(errByte)) + require.Equal(t, errWrapper.HTTPStatus, http.StatusForbidden) +} + +func testRoleAccess(t *testing.T, roleName string) { + role, ok := auth.Roles()[roleName] + require.Truef(t, ok, "invalid role name") harness := lab.NewHarness() lab.Pack(harness, fixtures.BHAdminApiClientFixture) - powerUserClientFixture := fixtures.NewUserApiClientFixture(fixtures.BHAdminApiClientFixture, auth.RolePowerUser) - lab.Pack(harness, powerUserClientFixture) + userClientFixture := fixtures.NewUserApiClientFixture(fixtures.BHAdminApiClientFixture, role.Name) + lab.Pack(harness, userClientFixture) lab.NewSpec(t, harness).Run( - lab.TestCase("SHOULD be able to access AppReadApplicationConfiguration endpoints", func(assert *require.Assertions, harness *lab.Harness) { - powerUserClient, ok := lab.Unpack(harness, powerUserClientFixture) + lab.TestCase(fmt.Sprintf("%s be able to access AppReadApplicationConfiguration endpoints", testCondition(role, auth.Permissions().AppReadApplicationConfiguration)), func(assert *require.Assertions, harness *lab.Harness) { + userClient, ok := lab.Unpack(harness, userClientFixture) assert.True(ok) - _, err := powerUserClient.GetAppConfigs() - require.Nil(t, err) + _, err := userClient.GetAppConfigs() + if role.Permissions.Has(auth.Permissions().AppReadApplicationConfiguration) { + require.Nil(t, err) + } else { + requireForbidden(t, err) + } }), - lab.TestCase("SHOULD be able to access AppWriteApplicationConfiguration endpoints", func(assert *require.Assertions, harness *lab.Harness) { - powerUserClient, ok := lab.Unpack(harness, powerUserClientFixture) + lab.TestCase(fmt.Sprintf("%s be able to access AppWriteApplicationConfiguration endpoints", testCondition(role, auth.Permissions().AppWriteApplicationConfiguration)), func(assert *require.Assertions, harness *lab.Harness) { + userClient, ok := lab.Unpack(harness, userClientFixture) assert.True(ok) updatedPasswordExpirationWindowParameter := v2.AppConfigUpdateRequest{ @@ -60,90 +86,147 @@ func TestRole_PowerUser(t *testing.T) { "duration": "P30D", }, } - _, err := powerUserClient.PutAppConfig(updatedPasswordExpirationWindowParameter) - require.Nil(t, err) + _, err := userClient.PutAppConfig(updatedPasswordExpirationWindowParameter) + if role.Permissions.Has(auth.Permissions().AppWriteApplicationConfiguration) { + require.Nil(t, err) + } else { + requireForbidden(t, err) + } }), - lab.TestCase("SHOULD be able to access AuthCreateToken endpoints", func(assert *require.Assertions, harness *lab.Harness) { - powerUserClient, ok := lab.Unpack(harness, powerUserClientFixture) + lab.TestCase(fmt.Sprintf("%s be able to access own AuthCreateToken endpoints", testCondition(role, auth.Permissions().AuthCreateToken)), func(assert *require.Assertions, harness *lab.Harness) { + userClient, ok := lab.Unpack(harness, userClientFixture) assert.True(ok) - randomUserUuid, err := uuid.NewV4() - require.Nil(t, err) + user, err := userClient.GetSelf() + require.Nilf(t, err, "failed looking up user details") - _, err = powerUserClient.ListUserTokens(randomUserUuid) - require.Nil(t, err) + _, err = userClient.ListUserTokens(user.ID) + if role.Permissions.Has(auth.Permissions().AuthCreateToken) { + require.Nil(t, err) + } else { + requireForbidden(t, err) + } }), - lab.TestCase("SHOULD NOT be able to access AuthManageProviders endpoints", func(assert *require.Assertions, harness *lab.Harness) { - powerUserClient, ok := lab.Unpack(harness, powerUserClientFixture) + lab.TestCase(fmt.Sprintf("%s be able to access AuthManageProviders endpoints", testCondition(role, auth.Permissions().AuthManageProviders)), func(assert *require.Assertions, harness *lab.Harness) { + userClient, ok := lab.Unpack(harness, userClientFixture) assert.True(ok) - _, err := powerUserClient.ListSAMLIdentityProviders() - var errByte []byte - errByte, err = json.Marshal(err) - require.Nil(t, err) - - errWrapper := api.ErrorWrapper{} - err = json.Unmarshal(errByte, &errWrapper) - require.Nil(t, err) - require.Equal(t, errWrapper.HTTPStatus, http.StatusForbidden) + _, err := userClient.ListSAMLIdentityProviders() + if role.Permissions.Has(auth.Permissions().AuthManageProviders) { + require.Nil(t, err) + } else { + requireForbidden(t, err) + } }), - lab.TestCase("SHOULD be able to access AuthManageSelf endpoints", func(assert *require.Assertions, harness *lab.Harness) { - powerUserClient, ok := lab.Unpack(harness, powerUserClientFixture) + lab.TestCase(fmt.Sprintf("%s be able to access AuthManageSelf endpoints", testCondition(role, auth.Permissions().AuthManageSelf)), func(assert *require.Assertions, harness *lab.Harness) { + userClient, ok := lab.Unpack(harness, userClientFixture) assert.True(ok) - _, err := powerUserClient.ListPermissions() - require.Nil(t, err) + _, err := userClient.ListPermissions() + if role.Permissions.Has(auth.Permissions().AuthManageSelf) { + require.Nil(t, err) + } else { + requireForbidden(t, err) + } }), - lab.TestCase("SHOULD NOT be able to access AuthManageUsers endpoints", func(assert *require.Assertions, harness *lab.Harness) { - powerUserClient, ok := lab.Unpack(harness, powerUserClientFixture) + lab.TestCase(fmt.Sprintf("%s be able to access AuthManageUsers endpoints", testCondition(role, auth.Permissions().AuthManageUsers)), func(assert *require.Assertions, harness *lab.Harness) { + userClient, ok := lab.Unpack(harness, userClientFixture) assert.True(ok) - _, err := powerUserClient.ListAuditLogs(time.Now(), time.Now(), 0, 0) - require.NotNil(t, err) + _, err := userClient.ListAuditLogs(time.Now(), time.Now(), 0, 0) + if role.Permissions.Has(auth.Permissions().AuthManageUsers) { + require.Nil(t, err) + } else { + requireForbidden(t, err) + } + }), - var errByte []byte - errByte, err = json.Marshal(err) - require.Nil(t, err) + lab.TestCase(fmt.Sprintf("%s be able to access GraphDBWrite endpoints", testCondition(role, auth.Permissions().GraphDBWrite)), func(assert *require.Assertions, harness *lab.Harness) { + userClient, ok := lab.Unpack(harness, userClientFixture) + assert.True(ok) - errWrapper := api.ErrorWrapper{} - err = json.Unmarshal(errByte, &errWrapper) - require.Nil(t, err) - require.Equal(t, errWrapper.HTTPStatus, http.StatusForbidden) + _, err := userClient.CreateFileUploadTask() + if role.Permissions.Has(auth.Permissions().GraphDBWrite) { + require.Nil(t, err) + } else { + requireForbidden(t, err) + } }), - lab.TestCase("SHOULD be able to access GraphDbWrite endpoints", func(assert *require.Assertions, harness *lab.Harness) { - powerUserClient, ok := lab.Unpack(harness, powerUserClientFixture) + lab.TestCase(fmt.Sprintf("%s be able to access GraphDBRead endpoints", testCondition(role, auth.Permissions().GraphDBRead)), func(assert *require.Assertions, harness *lab.Harness) { + userClient, ok := lab.Unpack(harness, userClientFixture) assert.True(ok) - _, err := powerUserClient.CreateFileUploadTask() - require.Nil(t, err) + _, err := userClient.ListAssetGroups() + if role.Permissions.Has(auth.Permissions().GraphDBRead) { + require.Nil(t, err) + } else { + requireForbidden(t, err) + } }), - lab.TestCase("SHOULD be able to access GraphDbRead endpoints", func(assert *require.Assertions, harness *lab.Harness) { - powerUserClient, ok := lab.Unpack(harness, powerUserClientFixture) + lab.TestCase(fmt.Sprintf("%s be able to access SavedQueriesRead endpoints", testCondition(role, auth.Permissions().SavedQueriesRead)), func(assert *require.Assertions, harness *lab.Harness) { + userClient, ok := lab.Unpack(harness, userClientFixture) assert.True(ok) - _, err := powerUserClient.ListAssetGroups() - require.Nil(t, err) + _, err := userClient.ListSavedQueries() + if role.Permissions.Has(auth.Permissions().SavedQueriesRead) { + require.Nil(t, err) + } else { + requireForbidden(t, err) + } }), - lab.TestCase("SHOULD be able to access SavedQueriesRead endpoints", func(assert *require.Assertions, harness *lab.Harness) { - powerUserClient, ok := lab.Unpack(harness, powerUserClientFixture) + lab.TestCase(fmt.Sprintf("%s be able to access SavedQueriesWrite endpoints", testCondition(role, auth.Permissions().SavedQueriesWrite)), func(assert *require.Assertions, harness *lab.Harness) { + userClient, ok := lab.Unpack(harness, userClientFixture) assert.True(ok) - _, err := powerUserClient.ListPermissions() - require.Nil(t, err) + _, err := userClient.CreateSavedQuery() + if role.Permissions.Has(auth.Permissions().SavedQueriesWrite) { + require.Nil(t, err) + } else { + requireForbidden(t, err) + } }), + ) +} + +func TestRole_ReadOnly(t *testing.T) { + testRoleAccess(t, auth.RoleReadOnly) +} + +func TestRole_UploadOnly(t *testing.T) { + testRoleAccess(t, auth.RoleUploadOnly) +} + +func TestRole_User(t *testing.T) { + testRoleAccess(t, auth.RoleUser) +} + +func TestRole_PowerUser(t *testing.T) { + testRoleAccess(t, auth.RolePowerUser) +} - lab.TestCase("SHOULD be able to access SavedQueriesWrite endpoints", func(assert *require.Assertions, harness *lab.Harness) { - powerUserClient, ok := lab.Unpack(harness, powerUserClientFixture) +func TestRole_Administrator(t *testing.T) { + testRoleAccess(t, auth.RoleAdministrator) +} + +func TestRole_Administrator_ListOtherUserTokens(t *testing.T) { + harness := lab.NewHarness() + lab.Pack(harness, fixtures.BHAdminApiClientFixture) + lab.NewSpec(t, harness).Run( + lab.TestCase("Should be able to access AuthCreateToken endpoints for other users", func(assert *require.Assertions, harness *lab.Harness) { + adminClient, ok := lab.Unpack(harness, fixtures.BHAdminApiClientFixture) assert.True(ok) - _, err := powerUserClient.ListPermissions() + randoUser, err := uuid.NewV4() + require.Nilf(t, err, "failed to create rando user") + + _, err = adminClient.ListUserTokens(randoUser) require.Nil(t, err) }), ) From de9aa4b253733d90b8212146b019d7d3f19322c3 Mon Sep 17 00:00:00 2001 From: Mistah J <26472282+mistahj67@users.noreply.github.com> Date: Mon, 29 Jan 2024 14:07:46 -0700 Subject: [PATCH 6/8] fix: incorrect permissions endpoint string --- cmd/api/src/api/v2/apiclient/auth.go | 2 +- cmd/api/src/api/v2/auth/auth_test.go | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cmd/api/src/api/v2/apiclient/auth.go b/cmd/api/src/api/v2/apiclient/auth.go index 5594177a83..ec43722aad 100644 --- a/cmd/api/src/api/v2/apiclient/auth.go +++ b/cmd/api/src/api/v2/apiclient/auth.go @@ -364,7 +364,7 @@ func (s Client) UserRemoveRole(userID uuid.UUID, roleID int32) error { func (s Client) GetPermission(id int32) (model.Permission, error) { var permission model.Permission - if response, err := s.Request(http.MethodGet, fmt.Sprintf("api/v2/auth/permissions/%d", id), nil, nil); err != nil { + if response, err := s.Request(http.MethodGet, fmt.Sprintf("api/v2/permissions/%d", id), nil, nil); err != nil { return permission, err } else { defer response.Body.Close() diff --git a/cmd/api/src/api/v2/auth/auth_test.go b/cmd/api/src/api/v2/auth/auth_test.go index 5b525ef58d..4093b03956 100644 --- a/cmd/api/src/api/v2/auth/auth_test.go +++ b/cmd/api/src/api/v2/auth/auth_test.go @@ -240,7 +240,7 @@ func TestManagementResource_ListPermissions_SortingError(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() - endpoint := "/api/v2/auth/permissions" + endpoint := "/api/v2/permissions" mockDB := dbmocks.NewMockDatabase(mockCtrl) config, err := config.NewDefaultConfiguration() @@ -273,7 +273,7 @@ func TestManagementResource_ListPermissions_InvalidFilterPredicate(t *testing.T) mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() - endpoint := "/api/v2/auth/permissions" + endpoint := "/api/v2/permissions" mockDB := dbmocks.NewMockDatabase(mockCtrl) config, err := config.NewDefaultConfiguration() @@ -306,7 +306,7 @@ func TestManagementResource_ListPermissions_PredicateMismatchWithColumn(t *testi mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() - endpoint := "/api/v2/auth/permissions" + endpoint := "/api/v2/permissions" mockDB := dbmocks.NewMockDatabase(mockCtrl) config, err := config.NewDefaultConfiguration() @@ -339,7 +339,7 @@ func TestManagementResource_ListPermissions_DBError(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() - endpoint := "/api/v2/auth/permissions" + endpoint := "/api/v2/permissions" mockDB := dbmocks.NewMockDatabase(mockCtrl) mockDB.EXPECT().GetAllPermissions("authority desc, name", model.SQLFilter{SQLString: "name = ?", Params: []any{"foo"}}).Return(model.Permissions{}, fmt.Errorf("foo")) @@ -375,7 +375,7 @@ func TestManagementResource_ListPermissions(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() - endpoint := "/api/v2/auth/permissions" + endpoint := "/api/v2/permissions" perm1 := model.Permission{ Authority: "a", From 205b0d4ef1d9c67f5416dcd3673d59501d0cc3d4 Mon Sep 17 00:00:00 2001 From: Mistah J <26472282+mistahj67@users.noreply.github.com> Date: Mon, 29 Jan 2024 16:31:36 -0700 Subject: [PATCH 7/8] fix: lab harness --- cmd/api/src/auth/role_test.go | 5 +++-- cmd/api/src/test/lab/fixtures/apiclient.go | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cmd/api/src/auth/role_test.go b/cmd/api/src/auth/role_test.go index 8bcacf7f73..fb80b7d5e9 100644 --- a/cmd/api/src/auth/role_test.go +++ b/cmd/api/src/auth/role_test.go @@ -59,8 +59,9 @@ func testRoleAccess(t *testing.T, roleName string) { require.Truef(t, ok, "invalid role name") harness := lab.NewHarness() - lab.Pack(harness, fixtures.BHAdminApiClientFixture) - userClientFixture := fixtures.NewUserApiClientFixture(fixtures.BHAdminApiClientFixture, role.Name) + adminApiClientFixture := fixtures.NewAdminApiClientFixture(fixtures.NewApiFixture()) + lab.Pack(harness, adminApiClientFixture) + userClientFixture := fixtures.NewUserApiClientFixture(adminApiClientFixture, role.Name) lab.Pack(harness, userClientFixture) lab.NewSpec(t, harness).Run( diff --git a/cmd/api/src/test/lab/fixtures/apiclient.go b/cmd/api/src/test/lab/fixtures/apiclient.go index 29b6154295..2806ffbae1 100644 --- a/cmd/api/src/test/lab/fixtures/apiclient.go +++ b/cmd/api/src/test/lab/fixtures/apiclient.go @@ -65,8 +65,8 @@ func NewUserApiClientFixture(adminApiFixture *lab.Fixture[apiclient.Client], rol fixture := lab.NewFixture(func(harness *lab.Harness) (apiclient.Client, error) { if configFixture, ok := lab.Unpack(harness, ConfigFixture); !ok { return apiclient.Client{}, fmt.Errorf("unable to unpack ConfigFixture") - } else if adminClient, ok := lab.Unpack(harness, BHAdminApiClientFixture); !ok { - return apiclient.Client{}, fmt.Errorf("unable to unpack BHAdminApiClientFixture") + } else if adminClient, ok := lab.Unpack(harness, adminApiFixture); !ok { + return apiclient.Client{}, fmt.Errorf("unable to unpack adminApiFixture") } else if username, err := config.GenerateSecureRandomString(7); err != nil { return apiclient.Client{}, fmt.Errorf("unable to generate random username") } else if secret, err := config.GenerateRandomBase64String(32); err != nil { From 9321ba318ba2f2b782d1419533627f97b13dc41e Mon Sep 17 00:00:00 2001 From: Mistah J <26472282+mistahj67@users.noreply.github.com> Date: Tue, 30 Jan 2024 13:50:04 -0700 Subject: [PATCH 8/8] fix: use assert over require --- cmd/api/src/auth/role_test.go | 54 +++++++++++++++++------------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/cmd/api/src/auth/role_test.go b/cmd/api/src/auth/role_test.go index fb80b7d5e9..7e76c11c88 100644 --- a/cmd/api/src/auth/role_test.go +++ b/cmd/api/src/auth/role_test.go @@ -43,15 +43,15 @@ func testCondition(role auth.RoleTemplate, permission model.Permission) string { return "SHOULD NOT" } -func requireForbidden(t *testing.T, err error) { +func requireForbidden(assert *require.Assertions, err error) { var errByte []byte errByte, err = json.Marshal(err) - require.Nil(t, err) + assert.Nil(err) errWrapper := api.ErrorWrapper{} err = json.Unmarshal(errByte, &errWrapper) - require.Nilf(t, err, "Failed to unmarshal error %v", string(errByte)) - require.Equal(t, errWrapper.HTTPStatus, http.StatusForbidden) + assert.Nilf(err, "Failed to unmarshal error %v", string(errByte)) + assert.Equal(errWrapper.HTTPStatus, http.StatusForbidden) } func testRoleAccess(t *testing.T, roleName string) { @@ -71,9 +71,9 @@ func testRoleAccess(t *testing.T, roleName string) { _, err := userClient.GetAppConfigs() if role.Permissions.Has(auth.Permissions().AppReadApplicationConfiguration) { - require.Nil(t, err) + assert.Nil(err) } else { - requireForbidden(t, err) + requireForbidden(assert, err) } }), @@ -89,9 +89,9 @@ func testRoleAccess(t *testing.T, roleName string) { } _, err := userClient.PutAppConfig(updatedPasswordExpirationWindowParameter) if role.Permissions.Has(auth.Permissions().AppWriteApplicationConfiguration) { - require.Nil(t, err) + assert.Nil(err) } else { - requireForbidden(t, err) + requireForbidden(assert, err) } }), @@ -100,13 +100,13 @@ func testRoleAccess(t *testing.T, roleName string) { assert.True(ok) user, err := userClient.GetSelf() - require.Nilf(t, err, "failed looking up user details") + assert.Nilf(err, "failed looking up user details") _, err = userClient.ListUserTokens(user.ID) if role.Permissions.Has(auth.Permissions().AuthCreateToken) { - require.Nil(t, err) + assert.Nil(err) } else { - requireForbidden(t, err) + requireForbidden(assert, err) } }), @@ -116,9 +116,9 @@ func testRoleAccess(t *testing.T, roleName string) { _, err := userClient.ListSAMLIdentityProviders() if role.Permissions.Has(auth.Permissions().AuthManageProviders) { - require.Nil(t, err) + assert.Nil(err) } else { - requireForbidden(t, err) + requireForbidden(assert, err) } }), @@ -128,9 +128,9 @@ func testRoleAccess(t *testing.T, roleName string) { _, err := userClient.ListPermissions() if role.Permissions.Has(auth.Permissions().AuthManageSelf) { - require.Nil(t, err) + assert.Nil(err) } else { - requireForbidden(t, err) + requireForbidden(assert, err) } }), @@ -140,9 +140,9 @@ func testRoleAccess(t *testing.T, roleName string) { _, err := userClient.ListAuditLogs(time.Now(), time.Now(), 0, 0) if role.Permissions.Has(auth.Permissions().AuthManageUsers) { - require.Nil(t, err) + assert.Nil(err) } else { - requireForbidden(t, err) + requireForbidden(assert, err) } }), @@ -152,9 +152,9 @@ func testRoleAccess(t *testing.T, roleName string) { _, err := userClient.CreateFileUploadTask() if role.Permissions.Has(auth.Permissions().GraphDBWrite) { - require.Nil(t, err) + assert.Nil(err) } else { - requireForbidden(t, err) + requireForbidden(assert, err) } }), @@ -164,9 +164,9 @@ func testRoleAccess(t *testing.T, roleName string) { _, err := userClient.ListAssetGroups() if role.Permissions.Has(auth.Permissions().GraphDBRead) { - require.Nil(t, err) + assert.Nil(err) } else { - requireForbidden(t, err) + requireForbidden(assert, err) } }), @@ -176,9 +176,9 @@ func testRoleAccess(t *testing.T, roleName string) { _, err := userClient.ListSavedQueries() if role.Permissions.Has(auth.Permissions().SavedQueriesRead) { - require.Nil(t, err) + assert.Nil(err) } else { - requireForbidden(t, err) + requireForbidden(assert, err) } }), @@ -188,9 +188,9 @@ func testRoleAccess(t *testing.T, roleName string) { _, err := userClient.CreateSavedQuery() if role.Permissions.Has(auth.Permissions().SavedQueriesWrite) { - require.Nil(t, err) + assert.Nil(err) } else { - requireForbidden(t, err) + requireForbidden(assert, err) } }), ) @@ -225,10 +225,10 @@ func TestRole_Administrator_ListOtherUserTokens(t *testing.T) { assert.True(ok) randoUser, err := uuid.NewV4() - require.Nilf(t, err, "failed to create rando user") + assert.Nilf(err, "failed to create rando user") _, err = adminClient.ListUserTokens(randoUser) - require.Nil(t, err) + assert.Nil(err) }), ) }