Skip to content

Commit

Permalink
BED-3995 - New role "Power User" (#343)
Browse files Browse the repository at this point in the history
Co-authored-by: Mistah J <[email protected]>
  • Loading branch information
elikmiller and mistahj67 authored Jan 30, 2024
1 parent dcdd8ae commit b364762
Show file tree
Hide file tree
Showing 8 changed files with 412 additions and 59 deletions.
4 changes: 2 additions & 2 deletions cmd/api/src/api/v2/apiclient/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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()
Expand Down
43 changes: 43 additions & 0 deletions cmd/api/src/api/v2/apiclient/savedqueries.go
Original file line number Diff line number Diff line change
@@ -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)
}
}
10 changes: 5 additions & 5 deletions cmd/api/src/api/v2/auth/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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"))

Expand Down Expand Up @@ -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",
Expand Down
10 changes: 5 additions & 5 deletions cmd/api/src/api/v2/cypher_search_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand All @@ -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"
Expand All @@ -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{
Expand Down
74 changes: 36 additions & 38 deletions cmd/api/src/auth/permission.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
}
}
35 changes: 28 additions & 7 deletions cmd/api/src/auth/role.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const (
RoleUploadOnly = "Upload-Only"
RoleReadOnly = "Read-Only"
RoleUser = "User"
RolePowerUser = "Power User"
RoleAdministrator = "Administrator"
)

Expand Down Expand Up @@ -70,32 +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,
},
},
RolePowerUser: {
Name: RolePowerUser,
Description: "Can upload data, manage clients, and perform any action a User can",
Permissions: model.Permissions{
permissions.AppReadApplicationConfiguration,
permissions.AppWriteApplicationConfiguration,
permissions.APsGenerateReport,
permissions.APsManageAPs,
permissions.AuthCreateToken,
permissions.AuthManageSelf,
permissions.ClientsManage,
permissions.ClientsRead,
permissions.ClientsTasking,
permissions.CollectionManageJobs,
permissions.GraphDBWrite,
permissions.GraphDBRead,
permissions.SavedQueriesRead,
permissions.SavedQueriesWrite,
},
},
RoleAdministrator: {
Expand Down
Loading

0 comments on commit b364762

Please sign in to comment.