diff --git a/client/app_role_assignments.go b/client/app_role_assignments.go
index 09659f0..c497724 100644
--- a/client/app_role_assignments.go
+++ b/client/app_role_assignments.go
@@ -20,100 +20,24 @@ package client
import (
"context"
"fmt"
- "net/url"
- "strings"
"github.com/bloodhoundad/azurehound/v2/client/query"
- "github.com/bloodhoundad/azurehound/v2/client/rest"
"github.com/bloodhoundad/azurehound/v2/constants"
"github.com/bloodhoundad/azurehound/v2/models/azure"
- "github.com/bloodhoundad/azurehound/v2/panicrecovery"
- "github.com/bloodhoundad/azurehound/v2/pipeline"
)
-func (s *azureClient) GetAzureADAppRoleAssignments(ctx context.Context, servicePrincipalId string, filter, search, orderBy, expand string, selectCols []string, top int32, count bool) (azure.AppRoleAssignmentList, error) {
+// GetAzureADAppRoleAssignments https://learn.microsoft.com/en-us/graph/api/serviceprincipal-list-approleassignedto?view=graph-rest-1.0
+func (s *azureClient) ListAzureADAppRoleAssignments(ctx context.Context, servicePrincipalId string, params query.GraphParams) <-chan AzureResult[azure.AppRoleAssignment] {
var (
- path = fmt.Sprintf("/%s/servicePrincipals/%s/appRoleAssignedTo", constants.GraphApiVersion, servicePrincipalId)
- params = query.Params{Filter: filter, Search: search, OrderBy: orderBy, Select: selectCols, Top: top, Count: count, Expand: expand}
- headers map[string]string
- response azure.AppRoleAssignmentList
+ out = make(chan AzureResult[azure.AppRoleAssignment])
+ path = fmt.Sprintf("/%s/servicePrincipals/%s/appRoleAssignedTo", constants.GraphApiVersion, servicePrincipalId)
)
- count = count || search != "" || (filter != "" && orderBy != "") || strings.Contains(filter, "endsWith")
- if count {
- headers = make(map[string]string)
- headers["ConsistencyLevel"] = "eventual"
+ if params.Top == 0 {
+ params.Top = 999
}
- if res, err := s.msgraph.Get(ctx, path, params.AsMap(), headers); err != nil {
- return response, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return response, err
- } else {
- return response, nil
- }
-}
-
-func (s *azureClient) ListAzureADAppRoleAssignments(ctx context.Context, servicePrincipal, filter, search, orderBy, expand string, selectCols []string) <-chan azure.AppRoleAssignmentResult {
- out := make(chan azure.AppRoleAssignmentResult)
-
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
-
- var (
- errResult = azure.AppRoleAssignmentResult{}
- nextLink string
- )
- if list, err := s.GetAzureADAppRoleAssignments(ctx, servicePrincipal, filter, search, orderBy, expand, selectCols, 999, false); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.AppRoleAssignmentResult{Ok: u}); !ok {
- return
- }
- }
+ go getAzureObjectList[azure.AppRoleAssignment](s.msgraph, ctx, path, params, out)
- nextLink = list.NextLink
- for nextLink != "" {
- var list azure.AppRoleAssignmentList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if res, err := s.msgraph.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if err := rest.Decode(res.Body, &list); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.AppRoleAssignmentResult{Ok: u}); !ok {
- return
- }
- }
- nextLink = list.NextLink
- }
- }
- }
- }()
return out
}
diff --git a/client/apps.go b/client/apps.go
index fb60ed5..80ce4fa 100644
--- a/client/apps.go
+++ b/client/apps.go
@@ -19,296 +19,43 @@ package client
import (
"context"
+ "encoding/json"
"fmt"
- "net/url"
- "strings"
"github.com/bloodhoundad/azurehound/v2/client/query"
- "github.com/bloodhoundad/azurehound/v2/client/rest"
"github.com/bloodhoundad/azurehound/v2/constants"
- "github.com/bloodhoundad/azurehound/v2/enums"
"github.com/bloodhoundad/azurehound/v2/models/azure"
- "github.com/bloodhoundad/azurehound/v2/panicrecovery"
- "github.com/bloodhoundad/azurehound/v2/pipeline"
)
-func (s *azureClient) GetAzureADApp(ctx context.Context, objectId string, selectCols []string) (*azure.Application, error) {
+// ListAzureADApps https://learn.microsoft.com/en-us/graph/api/application-list?view=graph-rest-beta
+func (s *azureClient) ListAzureADApps(ctx context.Context, params query.GraphParams) <-chan AzureResult[azure.Application] {
var (
- path = fmt.Sprintf("/%s/applications/%s", constants.GraphApiVersion, objectId)
- params = query.Params{Select: selectCols}.AsMap()
- response azure.ApplicationList
+ out = make(chan AzureResult[azure.Application])
+ path = fmt.Sprintf("/%s/applications", constants.GraphApiVersion)
)
- if res, err := s.msgraph.Get(ctx, path, params, nil); err != nil {
- return nil, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return nil, err
- } else {
- return &response.Value[0], nil
- }
-}
-func (s *azureClient) GetAzureADAppOwners(ctx context.Context, objectId string, filter string, search string, orderBy string, selectCols []string, top int32, count bool) (azure.DirectoryObjectList, error) {
- var (
- path = fmt.Sprintf("/%s/applications/%s/owners", constants.GraphApiBetaVersion, objectId)
- params = query.Params{Filter: filter, Search: search, OrderBy: orderBy, Select: selectCols, Top: top, Count: count}.AsMap()
- response azure.DirectoryObjectList
- )
- if res, err := s.msgraph.Get(ctx, path, params, nil); err != nil {
- return response, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return response, err
- } else {
- return response, nil
+ if params.Top == 0 {
+ params.Top = 99
}
-}
-func (s *azureClient) GetAzureADAppMemberObjects(ctx context.Context, objectId string, securityEnabledOnly bool) (azure.MemberObjectList, error) {
- var (
- path = fmt.Sprintf("/%s/directoryObjects/%s/getMemberObjects", constants.GraphApiVersion, objectId)
- response azure.MemberObjectList
- body = map[string]bool{
- "securityEnabledOnly": securityEnabledOnly,
- }
- )
- if res, err := s.msgraph.Post(ctx, path, body, nil, nil); err != nil {
- return response, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return response, err
- } else {
- return response, nil
- }
+ go getAzureObjectList[azure.Application](s.msgraph, ctx, path, params, out)
+ return out
}
-func (s *azureClient) GetAzureADApps(ctx context.Context, filter, search, orderBy, expand string, selectCols []string, top int32, count bool) (azure.ApplicationList, error) {
+// ListAzureADAppOwners https://learn.microsoft.com/en-us/graph/api/application-list-owners?view=graph-rest-beta
+func (s *azureClient) ListAzureADAppOwners(ctx context.Context, objectId string, params query.GraphParams) <-chan AzureResult[json.RawMessage] {
+
var (
- path = fmt.Sprintf("/%s/applications", constants.GraphApiVersion)
- params = query.Params{Filter: filter, Search: search, OrderBy: orderBy, Select: selectCols, Top: top, Count: count, Expand: expand}
- headers map[string]string
- response azure.ApplicationList
+ out = make(chan AzureResult[json.RawMessage])
+ path = fmt.Sprintf("/%s/applications/%s/owners", constants.GraphApiBetaVersion, objectId)
)
- count = count || search != "" || (filter != "" && orderBy != "") || strings.Contains(filter, "endsWith")
- if count {
- headers = make(map[string]string)
- headers["ConsistencyLevel"] = "eventual"
- }
- if res, err := s.msgraph.Get(ctx, path, params.AsMap(), headers); err != nil {
- return response, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return response, err
- } else {
- return response, nil
+ if params.Top == 0 {
+ params.Top = 99
}
-}
-
-func (s *azureClient) ListAzureADApps(ctx context.Context, filter, search, orderBy, expand string, selectCols []string) <-chan azure.ApplicationResult {
- out := make(chan azure.ApplicationResult)
-
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
-
- var (
- errResult = azure.ApplicationResult{}
- nextLink string
- )
-
- if list, err := s.GetAzureADApps(ctx, filter, search, orderBy, expand, selectCols, 999, false); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.ApplicationResult{Ok: u}); !ok {
- return
- }
- }
-
- nextLink = list.NextLink
- for nextLink != "" {
- var list azure.ApplicationList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- return
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- return
- } else if res, err := s.msgraph.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- return
- } else if err := rest.Decode(res.Body, &list); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- return
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.ApplicationResult{Ok: u}); !ok {
- return
- }
- }
- nextLink = list.NextLink
- }
- }
- }
- }()
- return out
-}
-
-func (s *azureClient) ListAzureADAppOwners(ctx context.Context, objectId string, filter, search, orderBy string, selectCols []string) <-chan azure.AppOwnerResult {
- out := make(chan azure.AppOwnerResult)
-
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
-
- var (
- errResult = azure.AppOwnerResult{}
- nextLink string
- )
-
- if list, err := s.GetAzureADAppOwners(ctx, objectId, filter, search, orderBy, selectCols, 999, false); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.AppOwnerResult{
- AppId: objectId,
- Ok: u,
- }); !ok {
- return
- }
- }
-
- nextLink = list.NextLink
- for nextLink != "" {
- var list azure.DirectoryObjectList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- return
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- return
- } else if res, err := s.msgraph.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- return
- } else if err := rest.Decode(res.Body, &list); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- return
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.AppOwnerResult{
- AppId: objectId,
- Ok: u,
- }); !ok {
- return
- }
- }
- nextLink = list.NextLink
- }
- }
- }
- }()
- return out
-}
-
-func (s *azureClient) ListAzureADAppMemberObjects(ctx context.Context, objectId string, securityEnabledOnly bool) <-chan azure.MemberObjectResult {
- out := make(chan azure.MemberObjectResult)
-
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
- var (
- errResult = azure.MemberObjectResult{
- ParentId: objectId,
- ParentType: string(enums.EntityApplication),
- }
- nextLink string
- )
- if list, err := s.GetAzureADAppMemberObjects(ctx, objectId, securityEnabledOnly); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.MemberObjectResult{
- ParentId: objectId,
- ParentType: string(enums.EntityApplication),
- Ok: u,
- }); !ok {
- return
- }
- }
+ go getAzureObjectList[json.RawMessage](s.msgraph, ctx, path, params, out)
- nextLink = list.NextLink
- for nextLink != "" {
- var list azure.MemberObjectList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if res, err := s.msgraph.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if err := rest.Decode(res.Body, &list); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.MemberObjectResult{
- ParentId: objectId,
- ParentType: string(enums.EntityApplication),
- Ok: u,
- }); !ok {
- return
- }
- }
- nextLink = list.NextLink
- }
- }
- }
- }()
return out
}
diff --git a/client/automation_accounts.go b/client/automation_accounts.go
index 512271b..67e8a23 100644
--- a/client/automation_accounts.go
+++ b/client/automation_accounts.go
@@ -20,114 +20,20 @@ package client
import (
"context"
"fmt"
- "net/url"
"github.com/bloodhoundad/azurehound/v2/client/query"
- "github.com/bloodhoundad/azurehound/v2/client/rest"
"github.com/bloodhoundad/azurehound/v2/models/azure"
- "github.com/bloodhoundad/azurehound/v2/panicrecovery"
- "github.com/bloodhoundad/azurehound/v2/pipeline"
)
-func (s *azureClient) GetAzureAutomationAccount(ctx context.Context, subscriptionId, groupName, aaName, expand string) (*azure.AutomationAccount, error) {
+// ListAzureAutomationAccounts https://learn.microsoft.com/en-us/rest/api/automation/automation-account/list?view=rest-automation-2021-06-22
+func (s *azureClient) ListAzureAutomationAccounts(ctx context.Context, subscriptionId string) <-chan AzureResult[azure.AutomationAccount] {
var (
- path = fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Automation/automationAccounts/%s", subscriptionId, groupName, aaName)
- params = query.Params{ApiVersion: "2021-07-01", Expand: expand}.AsMap()
- headers map[string]string
- response azure.AutomationAccount
+ out = make(chan AzureResult[azure.AutomationAccount])
+ path = fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Automation/automationAccounts", subscriptionId)
+ params = query.RMParams{ApiVersion: "2021-06-22"}
)
- if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
- return nil, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return nil, err
- } else {
- return &response, nil
- }
-}
-
-func (s *azureClient) GetAzureAutomationAccounts(ctx context.Context, subscriptionId string) (azure.AutomationAccountList, error) {
- var (
- path = fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Automation/automationAccounts", subscriptionId)
- params = query.Params{ApiVersion: "2021-06-22"}.AsMap()
- headers map[string]string
- response azure.AutomationAccountList
- )
-
- if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
- return response, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return response, err
- } else {
- return response, nil
- }
-}
-
-func (s *azureClient) ListAzureAutomationAccounts(ctx context.Context, subscriptionId string) <-chan azure.AutomationAccountResult {
- out := make(chan azure.AutomationAccountResult)
-
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
-
- var (
- errResult = azure.AutomationAccountResult{
- SubscriptionId: subscriptionId,
- }
- nextLink string
- )
- if result, err := s.GetAzureAutomationAccounts(ctx, subscriptionId); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range result.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.AutomationAccountResult{SubscriptionId: subscriptionId, Ok: u}); !ok {
- return
- }
- }
+ go getAzureObjectList[azure.AutomationAccount](s.resourceManager, ctx, path, params, out)
- nextLink = result.NextLink
- for nextLink != "" {
- var list azure.AutomationAccountList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if res, err := s.resourceManager.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if err := rest.Decode(res.Body, &list); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.AutomationAccountResult{
- SubscriptionId: "/subscriptions/" + subscriptionId,
- Ok: u,
- }); !ok {
- return
- }
- }
- nextLink = list.NextLink
- }
- }
- }
- }()
return out
}
diff --git a/client/client.go b/client/client.go
index 03e5a76..80e6401 100644
--- a/client/client.go
+++ b/client/client.go
@@ -23,10 +23,15 @@ import (
"context"
"encoding/json"
"fmt"
+ "net/http"
+ "net/url"
"github.com/bloodhoundad/azurehound/v2/client/config"
+ "github.com/bloodhoundad/azurehound/v2/client/query"
"github.com/bloodhoundad/azurehound/v2/client/rest"
"github.com/bloodhoundad/azurehound/v2/models/azure"
+ "github.com/bloodhoundad/azurehound/v2/panicrecovery"
+ "github.com/bloodhoundad/azurehound/v2/pipeline"
)
func NewClient(config config.Config) (AzureClient, error) {
@@ -86,87 +91,142 @@ func initClientViaGraph(msgraph, resourceManager rest.RestClient) (AzureClient,
}
}
+type AzureResult[T any] struct {
+ Error error
+ Ok T
+}
+
+func getAzureObjectList[T any](client rest.RestClient, ctx context.Context, path string, params query.Params, out chan AzureResult[T]) {
+ defer panicrecovery.PanicRecovery()
+ defer close(out)
+
+ var (
+ errResult AzureResult[T]
+ nextLink string
+ )
+
+ for {
+ var (
+ list struct {
+ CountGraph int `json:"@odata.count,omitempty"` // The total count of all graph results
+ NextLinkGraph string `json:"@odata.nextLink,omitempty"` // The URL to use for getting the next set of graph values.
+ ContextGraph string `json:"@odata.context,omitempty"`
+ NextLinkRM string `json:"nextLink,omitempty"` // The URL to use for getting the next set of rm values.
+ Value []T `json:"value"` // A list of azure values
+ }
+ res *http.Response
+ err error
+ )
+
+ if nextLink != "" {
+ if nextUrl, err := url.Parse(nextLink); err != nil {
+ errResult.Error = err
+ _ = pipeline.Send(ctx.Done(), out, errResult)
+ return
+ } else {
+ paramsMap := make(map[string]string)
+ if params != nil {
+ paramsMap = params.AsMap()
+ }
+ if req, err := rest.NewRequest(ctx, "GET", nextUrl, nil, paramsMap, nil); err != nil {
+ errResult.Error = err
+ _ = pipeline.Send(ctx.Done(), out, errResult)
+ return
+ } else if res, err = client.Send(req); err != nil {
+ errResult.Error = err
+ _ = pipeline.Send(ctx.Done(), out, errResult)
+ return
+ }
+ }
+ } else {
+ if res, err = client.Get(ctx, path, params, nil); err != nil {
+ errResult.Error = err
+ _ = pipeline.Send(ctx.Done(), out, errResult)
+ return
+ }
+ }
+
+ if err := rest.Decode(res.Body, &list); err != nil {
+ errResult.Error = err
+ _ = pipeline.Send(ctx.Done(), out, errResult)
+ return
+ } else {
+ for _, u := range list.Value {
+ if ok := pipeline.Send(ctx.Done(), out, AzureResult[T]{Ok: u}); !ok {
+ return
+ }
+ }
+ }
+
+ if list.NextLinkRM == "" && list.NextLinkGraph == "" {
+ break
+ } else if list.NextLinkGraph != "" {
+ nextLink = list.NextLinkGraph
+ } else if list.NextLinkRM != "" {
+ nextLink = list.NextLinkRM
+ }
+ }
+}
+
type azureClient struct {
msgraph rest.RestClient
resourceManager rest.RestClient
tenant azure.Tenant
}
-func (s azureClient) TenantInfo() azure.Tenant {
- return s.tenant
+type AzureGraphClient interface {
+ GetAzureADOrganization(ctx context.Context, selectCols []string) (*azure.Organization, error)
+
+ ListAzureADGroups(ctx context.Context, params query.GraphParams) <-chan AzureResult[azure.Group]
+ ListAzureADGroupMembers(ctx context.Context, objectId string, params query.GraphParams) <-chan AzureResult[json.RawMessage]
+ ListAzureADGroupOwners(ctx context.Context, objectId string, params query.GraphParams) <-chan AzureResult[json.RawMessage]
+ ListAzureADAppOwners(ctx context.Context, objectId string, params query.GraphParams) <-chan AzureResult[json.RawMessage]
+ ListAzureADApps(ctx context.Context, params query.GraphParams) <-chan AzureResult[azure.Application]
+ ListAzureADUsers(ctx context.Context, params query.GraphParams) <-chan AzureResult[azure.User]
+ ListAzureADRoleAssignments(ctx context.Context, params query.GraphParams) <-chan AzureResult[azure.UnifiedRoleAssignment]
+ ListAzureADRoles(ctx context.Context, params query.GraphParams) <-chan AzureResult[azure.Role]
+ ListAzureADServicePrincipalOwners(ctx context.Context, objectId string, params query.GraphParams) <-chan AzureResult[json.RawMessage]
+ ListAzureADServicePrincipals(ctx context.Context, params query.GraphParams) <-chan AzureResult[azure.ServicePrincipal]
+ ListAzureDeviceRegisteredOwners(ctx context.Context, objectId string, params query.GraphParams) <-chan AzureResult[json.RawMessage]
+ ListAzureDevices(ctx context.Context, params query.GraphParams) <-chan AzureResult[azure.Device]
+ ListAzureADAppRoleAssignments(ctx context.Context, servicePrincipalId string, params query.GraphParams) <-chan AzureResult[azure.AppRoleAssignment]
}
-func (s azureClient) CloseIdleConnections() {
- s.msgraph.CloseIdleConnections()
- s.resourceManager.CloseIdleConnections()
+type AzureResourceManagerClient interface {
+ GetAzureADTenants(ctx context.Context, includeAllTenantCategories bool) (azure.TenantList, error)
+
+ ListRoleAssignmentsForResource(ctx context.Context, resourceId string, filter, tenantId string) <-chan AzureResult[azure.RoleAssignment]
+ ListAzureADTenants(ctx context.Context, includeAllTenantCategories bool) <-chan AzureResult[azure.Tenant]
+ ListAzureContainerRegistries(ctx context.Context, subscriptionId string) <-chan AzureResult[azure.ContainerRegistry]
+ ListAzureWebApps(ctx context.Context, subscriptionId string) <-chan AzureResult[azure.WebApp]
+ ListAzureManagedClusters(ctx context.Context, subscriptionId string) <-chan AzureResult[azure.ManagedCluster]
+ ListAzureVMScaleSets(ctx context.Context, subscriptionId string) <-chan AzureResult[azure.VMScaleSet]
+ ListAzureKeyVaults(ctx context.Context, subscriptionId string, params query.RMParams) <-chan AzureResult[azure.KeyVault]
+ ListAzureManagementGroups(ctx context.Context, skipToken string) <-chan AzureResult[azure.ManagementGroup]
+ ListAzureManagementGroupDescendants(ctx context.Context, groupId string, top int32) <-chan AzureResult[azure.DescendantInfo]
+ ListAzureResourceGroups(ctx context.Context, subscriptionId string, params query.RMParams) <-chan AzureResult[azure.ResourceGroup]
+ ListAzureSubscriptions(ctx context.Context) <-chan AzureResult[azure.Subscription]
+ ListAzureVirtualMachines(ctx context.Context, subscriptionId string, params query.RMParams) <-chan AzureResult[azure.VirtualMachine]
+ ListAzureStorageAccounts(ctx context.Context, subscriptionId string) <-chan AzureResult[azure.StorageAccount]
+ ListAzureStorageContainers(ctx context.Context, subscriptionId string, resourceGroupName string, saName string, filter string, includeDeleted string, maxPageSize string) <-chan AzureResult[azure.StorageContainer]
+ ListAzureAutomationAccounts(ctx context.Context, subscriptionId string) <-chan AzureResult[azure.AutomationAccount]
+ ListAzureLogicApps(ctx context.Context, subscriptionId string, filter string, top int32) <-chan AzureResult[azure.LogicApp]
+ ListAzureFunctionApps(ctx context.Context, subscriptionId string) <-chan AzureResult[azure.FunctionApp]
}
type AzureClient interface {
- GetAzureADApp(ctx context.Context, objectId string, selectCols []string) (*azure.Application, error)
- GetAzureADApps(ctx context.Context, filter, search, orderBy, expand string, selectCols []string, top int32, count bool) (azure.ApplicationList, error)
- GetAzureADDirectoryObject(ctx context.Context, objectId string) (json.RawMessage, error)
- GetAzureADGroup(ctx context.Context, objectId string, selectCols []string) (*azure.Group, error)
- GetAzureADGroupOwners(ctx context.Context, objectId string, filter string, search string, orderBy string, selectCols []string, top int32, count bool) (azure.DirectoryObjectList, error)
- GetAzureADGroups(ctx context.Context, filter, search, orderBy, expand string, selectCols []string, top int32, count bool) (azure.GroupList, error)
- GetAzureADOrganization(ctx context.Context, selectCols []string) (*azure.Organization, error)
- GetAzureADRole(ctx context.Context, roleId string, selectCols []string) (*azure.Role, error)
- GetAzureADRoleAssignment(ctx context.Context, objectId string, selectCols []string) (*azure.UnifiedRoleAssignment, error)
- GetAzureADRoleAssignments(ctx context.Context, filter, search, orderBy, expand string, selectCols []string, top int32, count bool) (azure.UnifiedRoleAssignmentList, error)
- GetAzureADRoles(ctx context.Context, filter, expand string) (azure.RoleList, error)
- GetAzureADServicePrincipal(ctx context.Context, objectId string, selectCols []string) (*azure.ServicePrincipal, error)
- GetAzureADServicePrincipalOwners(ctx context.Context, objectId string, filter string, search string, orderBy string, selectCols []string, top int32, count bool) (azure.DirectoryObjectList, error)
- GetAzureADServicePrincipals(ctx context.Context, filter, search, orderBy, expand string, selectCols []string, top int32, count bool) (azure.ServicePrincipalList, error)
- GetAzureADTenants(ctx context.Context, includeAllTenantCategories bool) (azure.TenantList, error)
- GetAzureADUser(ctx context.Context, objectId string, selectCols []string) (*azure.User, error)
- GetAzureADUsers(ctx context.Context, filter string, search string, orderBy string, selectCols []string, top int32, count bool) (azure.UserList, error)
- GetAzureDevice(ctx context.Context, objectId string, selectCols []string) (*azure.Device, error)
- GetAzureDevices(ctx context.Context, filter, search, orderBy, expand string, selectCols []string, top int32, count bool) (azure.DeviceList, error)
- GetAzureKeyVault(ctx context.Context, subscriptionId, groupName, vaultName string) (*azure.KeyVault, error)
- GetAzureKeyVaults(ctx context.Context, subscriptionId string, top int32) (azure.KeyVaultList, error)
- GetAzureManagementGroup(ctx context.Context, groupId, filter, expand string, recurse bool) (*azure.ManagementGroup, error)
- GetAzureManagementGroups(ctx context.Context) (azure.ManagementGroupList, error)
- GetAzureResourceGroup(ctx context.Context, subscriptionId, groupName string) (*azure.ResourceGroup, error)
- GetAzureResourceGroups(ctx context.Context, subscriptionId string, filter string, top int32) (azure.ResourceGroupList, error)
- GetAzureSubscription(ctx context.Context, objectId string) (*azure.Subscription, error)
- GetAzureSubscriptions(ctx context.Context) (azure.SubscriptionList, error)
- GetAzureVirtualMachine(ctx context.Context, subscriptionId, groupName, vmName, expand string) (*azure.VirtualMachine, error)
- GetAzureVirtualMachines(ctx context.Context, subscriptionId string, statusOnly bool) (azure.VirtualMachineList, error)
- GetAzureStorageAccount(ctx context.Context, subscriptionId, groupName, saName, expand string) (*azure.StorageAccount, error)
- GetAzureStorageAccounts(ctx context.Context, subscriptionId string) (azure.StorageAccountList, error)
- GetResourceRoleAssignments(ctx context.Context, subscriptionId string, filter string, expand string) (azure.RoleAssignmentList, error)
- GetRoleAssignmentsForResource(ctx context.Context, resourceId string, filter string) (azure.RoleAssignmentList, error)
- ListAzureADAppMemberObjects(ctx context.Context, objectId string, securityEnabledOnly bool) <-chan azure.MemberObjectResult
- ListAzureADAppOwners(ctx context.Context, objectId string, filter, search, orderBy string, selectCols []string) <-chan azure.AppOwnerResult
- ListAzureADApps(ctx context.Context, filter, search, orderBy, expand string, selectCols []string) <-chan azure.ApplicationResult
- ListAzureADGroupMembers(ctx context.Context, objectId string, filter, search, orderBy string, selectCols []string) <-chan azure.MemberObjectResult
- ListAzureADGroupOwners(ctx context.Context, objectId string, filter, search, orderBy string, selectCols []string) <-chan azure.GroupOwnerResult
- ListAzureADGroups(ctx context.Context, filter, search, orderBy, expand string, selectCols []string) <-chan azure.GroupResult
- ListAzureADRoleAssignments(ctx context.Context, filter, search, orderBy, expand string, selectCols []string) <-chan azure.UnifiedRoleAssignmentResult
- ListAzureADRoles(ctx context.Context, filter, expand string) <-chan azure.RoleResult
- ListAzureADServicePrincipalOwners(ctx context.Context, objectId string, filter, search, orderBy string, selectCols []string) <-chan azure.ServicePrincipalOwnerResult
- ListAzureADServicePrincipals(ctx context.Context, filter, search, orderBy, expand string, selectCols []string) <-chan azure.ServicePrincipalResult
- ListAzureADTenants(ctx context.Context, includeAllTenantCategories bool) <-chan azure.TenantResult
- ListAzureADUsers(ctx context.Context, filter string, search string, orderBy string, selectCols []string) <-chan azure.UserResult
- ListAzureContainerRegistries(ctx context.Context, subscriptionId string) <-chan azure.ContainerRegistryResult
- ListAzureWebApps(ctx context.Context, subscriptionId string) <-chan azure.WebAppResult
- ListAzureManagedClusters(ctx context.Context, subscriptionId string, statusOnly bool) <-chan azure.ManagedClusterResult
- ListAzureVMScaleSets(ctx context.Context, subscriptionId string, statusOnly bool) <-chan azure.VMScaleSetResult
- ListAzureDeviceRegisteredOwners(ctx context.Context, objectId string, securityEnabledOnly bool) <-chan azure.DeviceRegisteredOwnerResult
- ListAzureDevices(ctx context.Context, filter, search, orderBy, expand string, selectCols []string) <-chan azure.DeviceResult
- ListAzureKeyVaults(ctx context.Context, subscriptionId string, top int32) <-chan azure.KeyVaultResult
- ListAzureManagementGroupDescendants(ctx context.Context, groupId string) <-chan azure.DescendantInfoResult
- ListAzureManagementGroups(ctx context.Context) <-chan azure.ManagementGroupResult
- ListAzureResourceGroups(ctx context.Context, subscriptionId, filter string) <-chan azure.ResourceGroupResult
- ListAzureSubscriptions(ctx context.Context) <-chan azure.SubscriptionResult
- ListAzureVirtualMachines(ctx context.Context, subscriptionId string, statusOnly bool) <-chan azure.VirtualMachineResult
- ListAzureStorageAccounts(ctx context.Context, subscriptionId string) <-chan azure.StorageAccountResult
- ListAzureStorageContainers(ctx context.Context, subscriptionId string, resourceGroupName string, saName string, filter string, includeDeleted string, maxPageSize string) <-chan azure.StorageContainerResult
- ListAzureAutomationAccounts(ctx context.Context, subscriptionId string) <-chan azure.AutomationAccountResult
- ListAzureLogicApps(ctx context.Context, subscriptionId string, filter string, top int32) <-chan azure.LogicAppResult
- ListAzureFunctionApps(ctx context.Context, subscriptionId string) <-chan azure.FunctionAppResult
- ListResourceRoleAssignments(ctx context.Context, subscriptionId string, filter string, expand string) <-chan azure.RoleAssignmentResult
- ListRoleAssignmentsForResource(ctx context.Context, resourceId string, filter string) <-chan azure.RoleAssignmentResult
- ListAzureADAppRoleAssignments(ctx context.Context, servicePrincipal, filter, search, orderBy, expand string, selectCols []string) <-chan azure.AppRoleAssignmentResult
+ AzureGraphClient
+ AzureResourceManagerClient
+
TenantInfo() azure.Tenant
CloseIdleConnections()
}
+
+func (s azureClient) TenantInfo() azure.Tenant {
+ return s.tenant
+}
+
+func (s azureClient) CloseIdleConnections() {
+ s.msgraph.CloseIdleConnections()
+ s.resourceManager.CloseIdleConnections()
+}
diff --git a/client/container_registries.go b/client/container_registries.go
index 9e7eebb..cc7d1ed 100644
--- a/client/container_registries.go
+++ b/client/container_registries.go
@@ -20,114 +20,20 @@ package client
import (
"context"
"fmt"
- "net/url"
"github.com/bloodhoundad/azurehound/v2/client/query"
- "github.com/bloodhoundad/azurehound/v2/client/rest"
"github.com/bloodhoundad/azurehound/v2/models/azure"
- "github.com/bloodhoundad/azurehound/v2/panicrecovery"
- "github.com/bloodhoundad/azurehound/v2/pipeline"
)
-func (s *azureClient) GetAzureContainerRegistry(ctx context.Context, subscriptionId, groupName, crName, expand string) (*azure.ContainerRegistry, error) {
+// ListAzureContainerRegistries https://learn.microsoft.com/en-us/rest/api/containerregistry/registries/list?view=rest-containerregistry-2023-01-01-preview
+func (s *azureClient) ListAzureContainerRegistries(ctx context.Context, subscriptionId string) <-chan AzureResult[azure.ContainerRegistry] {
var (
- path = fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.ContainerRegistry/registries/%s", subscriptionId, groupName, crName)
- params = query.Params{ApiVersion: "2023-01-01-preview", Expand: expand}.AsMap()
- headers map[string]string
- response azure.ContainerRegistry
+ out = make(chan AzureResult[azure.ContainerRegistry])
+ path = fmt.Sprintf("/subscriptions/%s/providers/Microsoft.ContainerRegistry/registries", subscriptionId)
+ params = query.RMParams{ApiVersion: "2023-01-01-preview"}
)
- if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
- return nil, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return nil, err
- } else {
- return &response, nil
- }
-}
-
-func (s *azureClient) GetAzureContainerRegistries(ctx context.Context, subscriptionId string) (azure.ContainerRegistryList, error) {
- var (
- path = fmt.Sprintf("/subscriptions/%s/providers/Microsoft.ContainerRegistry/registries", subscriptionId)
- params = query.Params{ApiVersion: "2023-01-01-preview"}.AsMap()
- headers map[string]string
- response azure.ContainerRegistryList
- )
-
- if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
- return response, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return response, err
- } else {
- return response, nil
- }
-}
-
-func (s *azureClient) ListAzureContainerRegistries(ctx context.Context, subscriptionId string) <-chan azure.ContainerRegistryResult {
- out := make(chan azure.ContainerRegistryResult)
-
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
-
- var (
- errResult = azure.ContainerRegistryResult{
- SubscriptionId: subscriptionId,
- }
- nextLink string
- )
- if result, err := s.GetAzureContainerRegistries(ctx, subscriptionId); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range result.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.ContainerRegistryResult{SubscriptionId: subscriptionId, Ok: u}); !ok {
- return
- }
- }
+ go getAzureObjectList[azure.ContainerRegistry](s.resourceManager, ctx, path, params, out)
- nextLink = result.NextLink
- for nextLink != "" {
- var list azure.ContainerRegistryList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if res, err := s.resourceManager.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if err := rest.Decode(res.Body, &list); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.ContainerRegistryResult{
- SubscriptionId: "/subscriptions/" + subscriptionId,
- Ok: u,
- }); !ok {
- return
- }
- }
- nextLink = list.NextLink
- }
- }
- }
- }()
return out
}
diff --git a/client/devices.go b/client/devices.go
index 823ab71..d4935a2 100644
--- a/client/devices.go
+++ b/client/devices.go
@@ -19,204 +19,38 @@ package client
import (
"context"
+ "encoding/json"
"fmt"
- "net/url"
- "strings"
"github.com/bloodhoundad/azurehound/v2/client/query"
- "github.com/bloodhoundad/azurehound/v2/client/rest"
"github.com/bloodhoundad/azurehound/v2/constants"
"github.com/bloodhoundad/azurehound/v2/models/azure"
- "github.com/bloodhoundad/azurehound/v2/panicrecovery"
- "github.com/bloodhoundad/azurehound/v2/pipeline"
)
-func (s *azureClient) GetAzureDevice(ctx context.Context, objectId string, selectCols []string) (*azure.Device, error) {
+// ListAzureDevices https://learn.microsoft.com/en-us/graph/api/device-list?view=graph-rest-1.0
+func (s *azureClient) ListAzureDevices(ctx context.Context, params query.GraphParams) <-chan AzureResult[azure.Device] {
var (
- path = fmt.Sprintf("/%s/devices/%s", constants.GraphApiVersion, objectId)
- params = query.Params{Select: selectCols}.AsMap()
- response azure.DeviceList
+ out = make(chan AzureResult[azure.Device])
+ path = fmt.Sprintf("/%s/devices", constants.GraphApiVersion)
)
- if res, err := s.msgraph.Get(ctx, path, params, nil); err != nil {
- return nil, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return nil, err
- } else {
- return &response.Value[0], nil
- }
-}
-func (s *azureClient) GetAzureDeviceRegisteredOwners(ctx context.Context, objectId string, filter, search string, count bool) (azure.DirectoryObjectList, error) {
- var (
- path = fmt.Sprintf("/%s/devices/%s/registeredOwners", constants.GraphApiBetaVersion, objectId)
- params = query.Params{Filter: filter, Search: search, Count: count}.AsMap()
- response azure.DirectoryObjectList
- )
- if res, err := s.msgraph.Get(ctx, path, params, nil); err != nil {
- return response, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return response, err
- } else {
- return response, nil
+ if params.Top == 0 {
+ params.Top = 999
}
-}
-func (s *azureClient) GetAzureDevices(ctx context.Context, filter, search, orderBy, expand string, selectCols []string, top int32, count bool) (azure.DeviceList, error) {
- var (
- path = fmt.Sprintf("/%s/devices", constants.GraphApiVersion)
- params = query.Params{Filter: filter, Search: search, OrderBy: orderBy, Select: selectCols, Top: top, Count: count, Expand: expand}
- headers map[string]string
- response azure.DeviceList
- )
+ go getAzureObjectList[azure.Device](s.msgraph, ctx, path, params, out)
- count = count || search != "" || (filter != "" && orderBy != "") || strings.Contains(filter, "endsWith")
- if count {
- headers = make(map[string]string)
- headers["ConsistencyLevel"] = "eventual"
- }
- if res, err := s.msgraph.Get(ctx, path, params.AsMap(), headers); err != nil {
- return response, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return response, err
- } else {
- return response, nil
- }
-}
-
-func (s *azureClient) ListAzureDevices(ctx context.Context, filter, search, orderBy, expand string, selectCols []string) <-chan azure.DeviceResult {
- out := make(chan azure.DeviceResult)
-
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
-
- var (
- errResult = azure.DeviceResult{}
- nextLink string
- )
-
- if list, err := s.GetAzureDevices(ctx, filter, search, orderBy, expand, selectCols, 999, false); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.DeviceResult{Ok: u}); !ok {
- return
- }
- }
-
- nextLink = list.NextLink
- for nextLink != "" {
- var list azure.DeviceList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if res, err := s.msgraph.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if err := rest.Decode(res.Body, &list); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.DeviceResult{Ok: u}); !ok {
- return
- }
- }
- nextLink = list.NextLink
- }
- }
- }
- }()
return out
}
-func (s *azureClient) ListAzureDeviceRegisteredOwners(ctx context.Context, objectId string, securityEnabledOnly bool) <-chan azure.DeviceRegisteredOwnerResult {
- out := make(chan azure.DeviceRegisteredOwnerResult)
-
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
-
- var (
- errResult = azure.DeviceRegisteredOwnerResult{
- DeviceId: objectId,
- }
- nextLink string
- )
+// ListAzureDeviceRegisteredOwners https://learn.microsoft.com/en-us/graph/api/device-list-registeredowners?view=graph-rest-beta
+func (s *azureClient) ListAzureDeviceRegisteredOwners(ctx context.Context, objectId string, params query.GraphParams) <-chan AzureResult[json.RawMessage] {
+ var (
+ out = make(chan AzureResult[json.RawMessage])
+ path = fmt.Sprintf("/%s/devices/%s/registeredOwners", constants.GraphApiBetaVersion, objectId)
+ )
- if list, err := s.GetAzureDeviceRegisteredOwners(ctx, objectId, "", "", false); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.DeviceRegisteredOwnerResult{
- DeviceId: objectId,
- Ok: u,
- }); !ok {
- return
- }
- }
+ go getAzureObjectList[json.RawMessage](s.msgraph, ctx, path, params, out)
- nextLink = list.NextLink
- for nextLink != "" {
- var list azure.DirectoryObjectList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if res, err := s.msgraph.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if err := rest.Decode(res.Body, &list); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.DeviceRegisteredOwnerResult{
- DeviceId: objectId,
- Ok: u,
- }); !ok {
- return
- }
- }
- nextLink = list.NextLink
- }
- }
- }
- }()
return out
}
diff --git a/client/directory_objects.go b/client/directory_objects.go
deleted file mode 100644
index 84ad165..0000000
--- a/client/directory_objects.go
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright (C) 2022 Specter Ops, Inc.
-//
-// This file is part of AzureHound.
-//
-// AzureHound is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// AzureHound is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see .
-
-package client
-
-import (
- "context"
- "encoding/json"
- "fmt"
- "io"
-
- "github.com/bloodhoundad/azurehound/v2/constants"
-)
-
-func (s *azureClient) GetAzureADDirectoryObject(ctx context.Context, objectId string) (json.RawMessage, error) {
- var (
- path = fmt.Sprintf("/%s/directoryObjects/%s", constants.GraphApiVersion, objectId)
- )
- if res, err := s.msgraph.Get(ctx, path, nil, nil); err != nil {
- return nil, err
- } else if body, err := io.ReadAll(res.Body); err != nil {
- res.Body.Close()
- return nil, err
- } else {
- res.Body.Close()
- return json.RawMessage(body), nil
- }
-}
diff --git a/client/function_apps.go b/client/function_apps.go
index 3e2e113..9c924d0 100644
--- a/client/function_apps.go
+++ b/client/function_apps.go
@@ -20,114 +20,20 @@ package client
import (
"context"
"fmt"
- "net/url"
"github.com/bloodhoundad/azurehound/v2/client/query"
- "github.com/bloodhoundad/azurehound/v2/client/rest"
"github.com/bloodhoundad/azurehound/v2/models/azure"
- "github.com/bloodhoundad/azurehound/v2/panicrecovery"
- "github.com/bloodhoundad/azurehound/v2/pipeline"
)
-func (s *azureClient) GetAzureFunctionApp(ctx context.Context, subscriptionId, groupName, functionAppName, expand string) (*azure.FunctionApp, error) {
+// ListAzureFunctionApps
+func (s *azureClient) ListAzureFunctionApps(ctx context.Context, subscriptionId string) <-chan AzureResult[azure.FunctionApp] {
var (
- path = fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Web/sites/%s", subscriptionId, groupName, functionAppName)
- params = query.Params{ApiVersion: "2022-03-01", Expand: expand}.AsMap()
- headers map[string]string
- response azure.FunctionApp
+ out = make(chan AzureResult[azure.FunctionApp])
+ path = fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Web/sites", subscriptionId)
+ params = query.RMParams{ApiVersion: "2022-03-01"}
)
- if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
- return nil, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return nil, err
- } else {
- return &response, nil
- }
-}
-
-func (s *azureClient) GetAzureFunctionApps(ctx context.Context, subscriptionId string) (azure.FunctionAppList, error) {
- var (
- path = fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Web/sites", subscriptionId)
- params = query.Params{ApiVersion: "2022-03-01"}.AsMap()
- headers map[string]string
- response azure.FunctionAppList
- )
-
- if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
- return response, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return response, err
- } else {
- return response, nil
- }
-}
-
-func (s *azureClient) ListAzureFunctionApps(ctx context.Context, subscriptionId string) <-chan azure.FunctionAppResult {
- out := make(chan azure.FunctionAppResult)
-
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
-
- var (
- errResult = azure.FunctionAppResult{
- SubscriptionId: subscriptionId,
- }
- nextLink string
- )
- if result, err := s.GetAzureFunctionApps(ctx, subscriptionId); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range result.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.FunctionAppResult{SubscriptionId: subscriptionId, Ok: u}); !ok {
- return
- }
- }
+ go getAzureObjectList[azure.FunctionApp](s.resourceManager, ctx, path, params, out)
- nextLink = result.NextLink
- for nextLink != "" {
- var list azure.FunctionAppList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if res, err := s.resourceManager.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if err := rest.Decode(res.Body, &list); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.FunctionAppResult{
- SubscriptionId: "/subscriptions/" + subscriptionId,
- Ok: u,
- }); !ok {
- return
- }
- }
- nextLink = list.NextLink
- }
- }
- }
- }()
return out
}
diff --git a/client/groups.go b/client/groups.go
index 5db0474..824c8fe 100644
--- a/client/groups.go
+++ b/client/groups.go
@@ -19,294 +19,54 @@ package client
import (
"context"
+ "encoding/json"
"fmt"
- "net/url"
- "strings"
"github.com/bloodhoundad/azurehound/v2/client/query"
- "github.com/bloodhoundad/azurehound/v2/client/rest"
"github.com/bloodhoundad/azurehound/v2/constants"
- "github.com/bloodhoundad/azurehound/v2/enums"
"github.com/bloodhoundad/azurehound/v2/models/azure"
- "github.com/bloodhoundad/azurehound/v2/panicrecovery"
- "github.com/bloodhoundad/azurehound/v2/pipeline"
)
-func (s *azureClient) GetAzureADGroup(ctx context.Context, objectId string, selectCols []string) (*azure.Group, error) {
+// ListAzureADGroups https://learn.microsoft.com/en-us/graph/api/group-list?view=graph-rest-beta
+func (s *azureClient) ListAzureADGroups(ctx context.Context, params query.GraphParams) <-chan AzureResult[azure.Group] {
var (
- path = fmt.Sprintf("/%s/groups/%s", constants.GraphApiVersion, objectId)
- params = query.Params{Select: selectCols}.AsMap()
- response azure.GroupList
+ out = make(chan AzureResult[azure.Group])
+ path = fmt.Sprintf("/%s/groups", constants.GraphApiVersion)
)
- if res, err := s.msgraph.Get(ctx, path, params, nil); err != nil {
- return nil, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return nil, err
- } else {
- return &response.Value[0], nil
- }
-}
-func (s *azureClient) GetAzureADGroupOwners(ctx context.Context, objectId string, filter string, search string, orderBy string, selectCols []string, top int32, count bool) (azure.DirectoryObjectList, error) {
- var (
- path = fmt.Sprintf("/%s/groups/%s/owners", constants.GraphApiBetaVersion, objectId)
- params = query.Params{Filter: filter, Search: search, OrderBy: orderBy, Select: selectCols, Top: top, Count: count}.AsMap()
- response azure.DirectoryObjectList
- )
- if res, err := s.msgraph.Get(ctx, path, params, nil); err != nil {
- return response, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return response, err
- } else {
- return response, nil
+ if params.Top == 0 {
+ params.Top = 99
}
-}
-func (s *azureClient) GetAzureADGroupMembers(ctx context.Context, objectId string, filter string, search string, count bool) (azure.MemberObjectList, error) {
- var (
- path = fmt.Sprintf("/%s/groups/%s/members", constants.GraphApiBetaVersion, objectId)
- params = query.Params{Filter: filter, Search: search, Count: count}.AsMap()
- response azure.MemberObjectList
- )
- if res, err := s.msgraph.Get(ctx, path, params, nil); err != nil {
- return response, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return response, err
- } else {
- return response, nil
- }
+ go getAzureObjectList[azure.Group](s.msgraph, ctx, path, params, out)
+
+ return out
}
-func (s *azureClient) GetAzureADGroups(ctx context.Context, filter, search, orderBy, expand string, selectCols []string, top int32, count bool) (azure.GroupList, error) {
+// ListAzureADGroupOwners https://learn.microsoft.com/en-us/graph/api/group-list-owners?view=graph-rest-beta
+func (s *azureClient) ListAzureADGroupOwners(ctx context.Context, objectId string, params query.GraphParams) <-chan AzureResult[json.RawMessage] {
var (
- path = fmt.Sprintf("/%s/groups", constants.GraphApiVersion)
- params = query.Params{Filter: filter, Search: search, OrderBy: orderBy, Select: selectCols, Top: top, Count: count, Expand: expand}
- headers map[string]string
- response azure.GroupList
+ out = make(chan AzureResult[json.RawMessage])
+ path = fmt.Sprintf("/%s/groups/%s/owners", constants.GraphApiBetaVersion, objectId)
)
- count = count || search != "" || (filter != "" && orderBy != "") || strings.Contains(filter, "endsWith")
- if count {
- headers = make(map[string]string)
- headers["ConsistencyLevel"] = "eventual"
+ if params.Top == 0 {
+ params.Top = 99
}
- if res, err := s.msgraph.Get(ctx, path, params.AsMap(), headers); err != nil {
- return response, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return response, err
- } else {
- return response, nil
- }
-}
-
-func (s *azureClient) ListAzureADGroups(ctx context.Context, filter, search, orderBy, expand string, selectCols []string) <-chan azure.GroupResult {
- out := make(chan azure.GroupResult)
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
+ go getAzureObjectList[json.RawMessage](s.msgraph, ctx, path, params, out)
- var (
- errResult = azure.GroupResult{}
- nextLink string
- )
-
- if list, err := s.GetAzureADGroups(ctx, filter, search, orderBy, expand, selectCols, 999, false); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.GroupResult{Ok: u}); !ok {
- return
- }
- }
-
- nextLink = list.NextLink
- for nextLink != "" {
- var list azure.GroupList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if res, err := s.msgraph.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if err := rest.Decode(res.Body, &list); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.GroupResult{Ok: u}); !ok {
- return
- }
- }
- nextLink = list.NextLink
- }
- }
- }
- }()
return out
}
-func (s *azureClient) ListAzureADGroupOwners(ctx context.Context, objectId string, filter, search, orderBy string, selectCols []string) <-chan azure.GroupOwnerResult {
- out := make(chan azure.GroupOwnerResult)
-
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
-
- var (
- errResult = azure.GroupOwnerResult{}
- nextLink string
- )
-
- if list, err := s.GetAzureADGroupOwners(ctx, objectId, filter, search, orderBy, selectCols, 999, false); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.GroupOwnerResult{
- GroupId: objectId,
- Ok: u,
- }); !ok {
- return
- }
- }
-
- nextLink = list.NextLink
- for nextLink != "" {
- var list azure.DirectoryObjectList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if res, err := s.msgraph.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if err := rest.Decode(res.Body, &list); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.GroupOwnerResult{
- GroupId: objectId,
- Ok: u,
- }); !ok {
- return
- }
- }
- nextLink = list.NextLink
- }
- }
- }
- }()
- return out
-}
-
-func (s *azureClient) ListAzureADGroupMembers(ctx context.Context, objectId string, filter, search, orderBy string, selectCols []string) <-chan azure.MemberObjectResult {
- out := make(chan azure.MemberObjectResult)
-
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
-
- var (
- errResult = azure.MemberObjectResult{
- ParentId: objectId,
- ParentType: string(enums.EntityGroup),
- }
- nextLink string
- )
+// ListAzureADGroupMembers https://learn.microsoft.com/en-us/graph/api/group-list-members?view=graph-rest-beta
+func (s *azureClient) ListAzureADGroupMembers(ctx context.Context, objectId string, params query.GraphParams) <-chan AzureResult[json.RawMessage] {
+ var (
+ out = make(chan AzureResult[json.RawMessage])
+ path = fmt.Sprintf("/%s/groups/%s/members", constants.GraphApiBetaVersion, objectId)
+ )
- if list, err := s.GetAzureADGroupMembers(ctx, objectId, filter, search, false); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.MemberObjectResult{
- ParentId: objectId,
- ParentType: string(enums.EntityGroup),
- Ok: u,
- }); !ok {
- return
- }
- }
+ go getAzureObjectList[json.RawMessage](s.msgraph, ctx, path, params, out)
- nextLink = list.NextLink
- for nextLink != "" {
- var list azure.MemberObjectList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if res, err := s.msgraph.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if err := rest.Decode(res.Body, &list); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.MemberObjectResult{
- ParentId: objectId,
- ParentType: string(enums.EntityGroup),
- Ok: u,
- }); !ok {
- return
- }
- }
- nextLink = list.NextLink
- }
- }
- }
- }()
return out
}
diff --git a/client/keyvaults.go b/client/keyvaults.go
index 56e33f7..c7735c7 100644
--- a/client/keyvaults.go
+++ b/client/keyvaults.go
@@ -20,117 +20,23 @@ package client
import (
"context"
"fmt"
- "net/url"
"github.com/bloodhoundad/azurehound/v2/client/query"
- "github.com/bloodhoundad/azurehound/v2/client/rest"
"github.com/bloodhoundad/azurehound/v2/models/azure"
- "github.com/bloodhoundad/azurehound/v2/panicrecovery"
- "github.com/bloodhoundad/azurehound/v2/pipeline"
)
-func (s *azureClient) GetAzureKeyVault(ctx context.Context, subscriptionId, groupName, vaultName string) (*azure.KeyVault, error) {
+// ListAzureKeyVaults https://learn.microsoft.com/en-us/rest/api/keyvault/keyvault/vaults/list-by-subscription?view=rest-keyvault-keyvault-2019-09-01
+func (s *azureClient) ListAzureKeyVaults(ctx context.Context, subscriptionId string, params query.RMParams) <-chan AzureResult[azure.KeyVault] {
var (
- path = fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.KeyVault/vaults/%s", subscriptionId, groupName, vaultName)
- params = query.Params{ApiVersion: "2019-09-01"}.AsMap()
- headers map[string]string
- response azure.KeyVault
- )
- if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
- return nil, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return nil, err
- } else {
- return &response, nil
- }
-}
-
-func (s *azureClient) GetAzureKeyVaults(ctx context.Context, subscriptionId string, top int32) (azure.KeyVaultList, error) {
- var (
- path = fmt.Sprintf("/subscriptions/%s/providers/Microsoft.KeyVault/vaults", subscriptionId)
- params = query.Params{ApiVersion: "2019-09-01", Top: top}.AsMap()
- headers map[string]string
- response azure.KeyVaultList
+ out = make(chan AzureResult[azure.KeyVault])
+ path = fmt.Sprintf("/subscriptions/%s/providers/Microsoft.KeyVault/vaults", subscriptionId)
)
- if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
- return response, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return response, err
- } else {
- return response, nil
+ if params.ApiVersion == "" {
+ params.ApiVersion = "2019-09-01"
}
-}
-
-func (s *azureClient) ListAzureKeyVaults(ctx context.Context, subscriptionId string, top int32) <-chan azure.KeyVaultResult {
- out := make(chan azure.KeyVaultResult)
-
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
-
- var (
- errResult = azure.KeyVaultResult{
- SubscriptionId: subscriptionId,
- }
- nextLink string
- )
- if result, err := s.GetAzureKeyVaults(ctx, subscriptionId, top); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range result.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.KeyVaultResult{
- SubscriptionId: subscriptionId,
- Ok: u,
- }); !ok {
- return
- }
- }
+ go getAzureObjectList[azure.KeyVault](s.resourceManager, ctx, path, params, out)
- nextLink = result.NextLink
- for nextLink != "" {
- var list azure.KeyVaultList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if res, err := s.resourceManager.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if err := rest.Decode(res.Body, &list); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.KeyVaultResult{
- SubscriptionId: subscriptionId,
- Ok: u,
- }); !ok {
- return
- }
- }
- nextLink = list.NextLink
- }
- }
- }
- }()
return out
}
diff --git a/client/logic_apps.go b/client/logic_apps.go
index 54006a5..711bfe2 100644
--- a/client/logic_apps.go
+++ b/client/logic_apps.go
@@ -20,114 +20,20 @@ package client
import (
"context"
"fmt"
- "net/url"
"github.com/bloodhoundad/azurehound/v2/client/query"
- "github.com/bloodhoundad/azurehound/v2/client/rest"
"github.com/bloodhoundad/azurehound/v2/models/azure"
- "github.com/bloodhoundad/azurehound/v2/panicrecovery"
- "github.com/bloodhoundad/azurehound/v2/pipeline"
)
-func (s *azureClient) GetAzureLogicApp(ctx context.Context, subscriptionId, groupName, logicappName, expand string) (*azure.LogicApp, error) {
+// ListAzureLogicApps https://learn.microsoft.com/en-us/rest/api/logic/workflows/list-by-subscription?view=rest-logic-2016-06-01
+func (s *azureClient) ListAzureLogicApps(ctx context.Context, subscriptionId string, filter string, top int32) <-chan AzureResult[azure.LogicApp] {
var (
- path = fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Logic/workflows/%s", subscriptionId, groupName, logicappName)
- params = query.Params{ApiVersion: "2016-06-01", Expand: expand}.AsMap()
- headers map[string]string
- response azure.LogicApp
+ out = make(chan AzureResult[azure.LogicApp])
+ path = fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Logic/workflows", subscriptionId)
+ params = query.RMParams{ApiVersion: "2016-06-01", Filter: filter, Top: top}
)
- if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
- return nil, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return nil, err
- } else {
- return &response, nil
- }
-}
-
-func (s *azureClient) GetAzureLogicApps(ctx context.Context, subscriptionId string, filter string, top int32) (azure.LogicAppList, error) {
- var (
- path = fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Logic/workflows", subscriptionId)
- params = query.Params{ApiVersion: "2016-06-01", Filter: filter, Top: top}.AsMap()
- headers map[string]string
- response azure.LogicAppList
- )
-
- if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
- return response, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return response, err
- } else {
- return response, nil
- }
-}
-
-func (s *azureClient) ListAzureLogicApps(ctx context.Context, subscriptionId string, filter string, top int32) <-chan azure.LogicAppResult {
- out := make(chan azure.LogicAppResult)
-
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
-
- var (
- errResult = azure.LogicAppResult{
- SubscriptionId: subscriptionId,
- }
- nextLink string
- )
- if result, err := s.GetAzureLogicApps(ctx, subscriptionId, filter, top); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range result.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.LogicAppResult{SubscriptionId: subscriptionId, Ok: u}); !ok {
- return
- }
- }
+ go getAzureObjectList[azure.LogicApp](s.resourceManager, ctx, path, params, out)
- nextLink = result.NextLink
- for nextLink != "" {
- var list azure.LogicAppList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if res, err := s.resourceManager.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if err := rest.Decode(res.Body, &list); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.LogicAppResult{
- SubscriptionId: "/subscriptions/" + subscriptionId,
- Ok: u,
- }); !ok {
- return
- }
- }
- nextLink = list.NextLink
- }
- }
- }
- }()
return out
}
diff --git a/client/managed_clusters.go b/client/managed_clusters.go
index b1db393..05c6b19 100644
--- a/client/managed_clusters.go
+++ b/client/managed_clusters.go
@@ -20,114 +20,20 @@ package client
import (
"context"
"fmt"
- "net/url"
"github.com/bloodhoundad/azurehound/v2/client/query"
- "github.com/bloodhoundad/azurehound/v2/client/rest"
"github.com/bloodhoundad/azurehound/v2/models/azure"
- "github.com/bloodhoundad/azurehound/v2/panicrecovery"
- "github.com/bloodhoundad/azurehound/v2/pipeline"
)
-func (s *azureClient) GetAzureManagedCluster(ctx context.Context, subscriptionId, groupName, mcName, expand string) (*azure.ManagedCluster, error) {
+// ListAzureManagedClusters https://learn.microsoft.com/en-us/rest/api/servicefabric/managedclusters/managed-clusters/list-by-subscription?view=rest-servicefabric-managedclusters-2021-07-01
+func (s *azureClient) ListAzureManagedClusters(ctx context.Context, subscriptionId string) <-chan AzureResult[azure.ManagedCluster] {
var (
- path = fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.ContainerService/managedClusters/%s", subscriptionId, groupName, mcName)
- params = query.Params{ApiVersion: "2021-07-01", Expand: expand}.AsMap()
- headers map[string]string
- response azure.ManagedCluster
+ out = make(chan AzureResult[azure.ManagedCluster])
+ path = fmt.Sprintf("/subscriptions/%s/providers/Microsoft.ContainerService/managedClusters", subscriptionId)
+ params = query.RMParams{ApiVersion: "2021-07-01"}
)
- if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
- return nil, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return nil, err
- } else {
- return &response, nil
- }
-}
-
-func (s *azureClient) GetAzureManagedClusters(ctx context.Context, subscriptionId string, statusOnly bool) (azure.ManagedClusterList, error) {
- var (
- path = fmt.Sprintf("/subscriptions/%s/providers/Microsoft.ContainerService/managedClusters", subscriptionId)
- params = query.Params{ApiVersion: "2021-07-01", StatusOnly: statusOnly}.AsMap()
- headers map[string]string
- response azure.ManagedClusterList
- )
-
- if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
- return response, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return response, err
- } else {
- return response, nil
- }
-}
-
-func (s *azureClient) ListAzureManagedClusters(ctx context.Context, subscriptionId string, statusOnly bool) <-chan azure.ManagedClusterResult {
- out := make(chan azure.ManagedClusterResult)
-
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
-
- var (
- errResult = azure.ManagedClusterResult{
- SubscriptionId: subscriptionId,
- }
- nextLink string
- )
- if result, err := s.GetAzureManagedClusters(ctx, subscriptionId, statusOnly); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range result.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.ManagedClusterResult{SubscriptionId: subscriptionId, Ok: u}); !ok {
- return
- }
- }
+ go getAzureObjectList[azure.ManagedCluster](s.resourceManager, ctx, path, params, out)
- nextLink = result.NextLink
- for nextLink != "" {
- var list azure.ManagedClusterList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if res, err := s.resourceManager.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if err := rest.Decode(res.Body, &list); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.ManagedClusterResult{
- SubscriptionId: "/subscriptions/" + subscriptionId,
- Ok: u,
- }); !ok {
- return
- }
- }
- nextLink = list.NextLink
- }
- }
- }
- }()
return out
}
diff --git a/client/management_groups.go b/client/management_groups.go
index f68d866..a269b92 100644
--- a/client/management_groups.go
+++ b/client/management_groups.go
@@ -20,191 +20,33 @@ package client
import (
"context"
"fmt"
- "net/url"
"github.com/bloodhoundad/azurehound/v2/client/query"
- "github.com/bloodhoundad/azurehound/v2/client/rest"
"github.com/bloodhoundad/azurehound/v2/models/azure"
- "github.com/bloodhoundad/azurehound/v2/panicrecovery"
- "github.com/bloodhoundad/azurehound/v2/pipeline"
)
-func (s *azureClient) GetAzureManagementGroup(ctx context.Context, groupId, filter, expand string, recurse bool) (*azure.ManagementGroup, error) {
+// ListAzureManagementGroups https://learn.microsoft.com/en-us/rest/api/managementgroups/management-groups/list?view=rest-managementgroups-2020-05-01
+func (s *azureClient) ListAzureManagementGroups(ctx context.Context, skipToken string) <-chan AzureResult[azure.ManagementGroup] {
var (
- path = fmt.Sprintf("/providers/Microsoft.Management/managementGroups/%s", groupId)
- params = query.Params{ApiVersion: "2020-05-01", Filter: filter, Expand: expand, Recurse: recurse}.AsMap()
- headers map[string]string
- response azure.ManagementGroup
+ out = make(chan AzureResult[azure.ManagementGroup])
+ path = "/providers/Microsoft.Management/managementGroups"
+ params = query.RMParams{ApiVersion: "2020-05-01", SkipToken: skipToken}
)
- if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
- return nil, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return nil, err
- } else {
- return &response, nil
- }
-}
-func (s *azureClient) GetAzureManagementGroups(ctx context.Context) (azure.ManagementGroupList, error) {
- var (
- path = "/providers/Microsoft.Management/managementGroups"
- params = query.Params{ApiVersion: "2020-05-01"}.AsMap()
- headers map[string]string
- response azure.ManagementGroupList
- )
+ go getAzureObjectList[azure.ManagementGroup](s.resourceManager, ctx, path, params, out)
- if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
- return response, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return response, err
- } else {
- return response, nil
- }
+ return out
}
-func (s *azureClient) GetAzureManagementGroupDescendants(ctx context.Context, groupId string, top int32) (azure.DescendantInfoList, error) {
+// ListAzureManagementGroupDescendants https://learn.microsoft.com/en-us/rest/api/managementgroups/management-groups/get-descendants?view=rest-managementgroups-2020-05-01
+func (s *azureClient) ListAzureManagementGroupDescendants(ctx context.Context, groupId string, top int32) <-chan AzureResult[azure.DescendantInfo] {
var (
- path = fmt.Sprintf("/providers/Microsoft.Management/managementGroups/%s/descendants", groupId)
- params = query.Params{ApiVersion: "2020-05-01", Top: top}.AsMap()
- headers map[string]string
- response azure.DescendantInfoList
+ out = make(chan AzureResult[azure.DescendantInfo])
+ path = fmt.Sprintf("/providers/Microsoft.Management/managementGroups/%s/descendants", groupId)
+ params = query.RMParams{ApiVersion: "2020-05-01", Top: top}
)
- if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
- return response, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return response, err
- } else {
- return response, nil
- }
-}
-
-func (s *azureClient) ListAzureManagementGroups(ctx context.Context) <-chan azure.ManagementGroupResult {
- out := make(chan azure.ManagementGroupResult)
-
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
-
- var (
- errResult = azure.ManagementGroupResult{}
- nextLink string
- )
-
- if result, err := s.GetAzureManagementGroups(ctx); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range result.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.ManagementGroupResult{Ok: u}); !ok {
- return
- }
- }
-
- nextLink = result.NextLink
- for nextLink != "" {
- var list azure.ManagementGroupList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if res, err := s.resourceManager.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if err := rest.Decode(res.Body, &list); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.ManagementGroupResult{Ok: u}); !ok {
- return
- }
- }
- nextLink = list.NextLink
- }
- }
- }
- }()
- return out
-}
-
-func (s *azureClient) ListAzureManagementGroupDescendants(ctx context.Context, groupId string) <-chan azure.DescendantInfoResult {
- out := make(chan azure.DescendantInfoResult)
-
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
-
- var (
- errResult = azure.DescendantInfoResult{}
- nextLink string
- )
-
- if result, err := s.GetAzureManagementGroupDescendants(ctx, groupId, 3000); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range result.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.DescendantInfoResult{Ok: u}); !ok {
- return
- }
- }
+ go getAzureObjectList[azure.DescendantInfo](s.resourceManager, ctx, path, params, out)
- nextLink = result.NextLink
- for nextLink != "" {
- var list azure.DescendantInfoList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if res, err := s.resourceManager.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if err := rest.Decode(res.Body, &list); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.DescendantInfoResult{Ok: u}); !ok {
- return
- }
- }
- nextLink = list.NextLink
- }
- }
- }
- }()
return out
}
diff --git a/client/mocks/client.go b/client/mocks/client.go
index fa2ca60..97dfeb3 100644
--- a/client/mocks/client.go
+++ b/client/mocks/client.go
@@ -5,12 +5,14 @@
package mocks
import (
- context "context"
- json "encoding/json"
- reflect "reflect"
-
- azure "github.com/bloodhoundad/azurehound/v2/models/azure"
- gomock "go.uber.org/mock/gomock"
+ "context"
+ "encoding/json"
+ "reflect"
+
+ "github.com/bloodhoundad/azurehound/v2/client"
+ "github.com/bloodhoundad/azurehound/v2/client/query"
+ "github.com/bloodhoundad/azurehound/v2/models/azure"
+ "go.uber.org/mock/gomock"
)
// MockAzureClient is a mock of AzureClient interface.
@@ -48,96 +50,6 @@ func (mr *MockAzureClientMockRecorder) CloseIdleConnections() *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CloseIdleConnections", reflect.TypeOf((*MockAzureClient)(nil).CloseIdleConnections))
}
-// GetAzureADApp mocks base method.
-func (m *MockAzureClient) GetAzureADApp(arg0 context.Context, arg1 string, arg2 []string) (*azure.Application, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetAzureADApp", arg0, arg1, arg2)
- ret0, _ := ret[0].(*azure.Application)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetAzureADApp indicates an expected call of GetAzureADApp.
-func (mr *MockAzureClientMockRecorder) GetAzureADApp(arg0, arg1, arg2 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureADApp", reflect.TypeOf((*MockAzureClient)(nil).GetAzureADApp), arg0, arg1, arg2)
-}
-
-// GetAzureADApps mocks base method.
-func (m *MockAzureClient) GetAzureADApps(arg0 context.Context, arg1, arg2, arg3, arg4 string, arg5 []string, arg6 int32, arg7 bool) (azure.ApplicationList, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetAzureADApps", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
- ret0, _ := ret[0].(azure.ApplicationList)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetAzureADApps indicates an expected call of GetAzureADApps.
-func (mr *MockAzureClientMockRecorder) GetAzureADApps(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureADApps", reflect.TypeOf((*MockAzureClient)(nil).GetAzureADApps), arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
-}
-
-// GetAzureADDirectoryObject mocks base method.
-func (m *MockAzureClient) GetAzureADDirectoryObject(arg0 context.Context, arg1 string) (json.RawMessage, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetAzureADDirectoryObject", arg0, arg1)
- ret0, _ := ret[0].(json.RawMessage)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetAzureADDirectoryObject indicates an expected call of GetAzureADDirectoryObject.
-func (mr *MockAzureClientMockRecorder) GetAzureADDirectoryObject(arg0, arg1 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureADDirectoryObject", reflect.TypeOf((*MockAzureClient)(nil).GetAzureADDirectoryObject), arg0, arg1)
-}
-
-// GetAzureADGroup mocks base method.
-func (m *MockAzureClient) GetAzureADGroup(arg0 context.Context, arg1 string, arg2 []string) (*azure.Group, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetAzureADGroup", arg0, arg1, arg2)
- ret0, _ := ret[0].(*azure.Group)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetAzureADGroup indicates an expected call of GetAzureADGroup.
-func (mr *MockAzureClientMockRecorder) GetAzureADGroup(arg0, arg1, arg2 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureADGroup", reflect.TypeOf((*MockAzureClient)(nil).GetAzureADGroup), arg0, arg1, arg2)
-}
-
-// GetAzureADGroupOwners mocks base method.
-func (m *MockAzureClient) GetAzureADGroupOwners(arg0 context.Context, arg1, arg2, arg3, arg4 string, arg5 []string, arg6 int32, arg7 bool) (azure.DirectoryObjectList, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetAzureADGroupOwners", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
- ret0, _ := ret[0].(azure.DirectoryObjectList)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetAzureADGroupOwners indicates an expected call of GetAzureADGroupOwners.
-func (mr *MockAzureClientMockRecorder) GetAzureADGroupOwners(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureADGroupOwners", reflect.TypeOf((*MockAzureClient)(nil).GetAzureADGroupOwners), arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
-}
-
-// GetAzureADGroups mocks base method.
-func (m *MockAzureClient) GetAzureADGroups(arg0 context.Context, arg1, arg2, arg3, arg4 string, arg5 []string, arg6 int32, arg7 bool) (azure.GroupList, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetAzureADGroups", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
- ret0, _ := ret[0].(azure.GroupList)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetAzureADGroups indicates an expected call of GetAzureADGroups.
-func (mr *MockAzureClientMockRecorder) GetAzureADGroups(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureADGroups", reflect.TypeOf((*MockAzureClient)(nil).GetAzureADGroups), arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
-}
-
// GetAzureADOrganization mocks base method.
func (m *MockAzureClient) GetAzureADOrganization(arg0 context.Context, arg1 []string) (*azure.Organization, error) {
m.ctrl.T.Helper()
@@ -153,111 +65,6 @@ func (mr *MockAzureClientMockRecorder) GetAzureADOrganization(arg0, arg1 interfa
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureADOrganization", reflect.TypeOf((*MockAzureClient)(nil).GetAzureADOrganization), arg0, arg1)
}
-// GetAzureADRole mocks base method.
-func (m *MockAzureClient) GetAzureADRole(arg0 context.Context, arg1 string, arg2 []string) (*azure.Role, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetAzureADRole", arg0, arg1, arg2)
- ret0, _ := ret[0].(*azure.Role)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetAzureADRole indicates an expected call of GetAzureADRole.
-func (mr *MockAzureClientMockRecorder) GetAzureADRole(arg0, arg1, arg2 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureADRole", reflect.TypeOf((*MockAzureClient)(nil).GetAzureADRole), arg0, arg1, arg2)
-}
-
-// GetAzureADRoleAssignment mocks base method.
-func (m *MockAzureClient) GetAzureADRoleAssignment(arg0 context.Context, arg1 string, arg2 []string) (*azure.UnifiedRoleAssignment, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetAzureADRoleAssignment", arg0, arg1, arg2)
- ret0, _ := ret[0].(*azure.UnifiedRoleAssignment)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetAzureADRoleAssignment indicates an expected call of GetAzureADRoleAssignment.
-func (mr *MockAzureClientMockRecorder) GetAzureADRoleAssignment(arg0, arg1, arg2 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureADRoleAssignment", reflect.TypeOf((*MockAzureClient)(nil).GetAzureADRoleAssignment), arg0, arg1, arg2)
-}
-
-// GetAzureADRoleAssignments mocks base method.
-func (m *MockAzureClient) GetAzureADRoleAssignments(arg0 context.Context, arg1, arg2, arg3, arg4 string, arg5 []string, arg6 int32, arg7 bool) (azure.UnifiedRoleAssignmentList, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetAzureADRoleAssignments", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
- ret0, _ := ret[0].(azure.UnifiedRoleAssignmentList)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetAzureADRoleAssignments indicates an expected call of GetAzureADRoleAssignments.
-func (mr *MockAzureClientMockRecorder) GetAzureADRoleAssignments(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureADRoleAssignments", reflect.TypeOf((*MockAzureClient)(nil).GetAzureADRoleAssignments), arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
-}
-
-// GetAzureADRoles mocks base method.
-func (m *MockAzureClient) GetAzureADRoles(arg0 context.Context, arg1, arg2 string) (azure.RoleList, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetAzureADRoles", arg0, arg1, arg2)
- ret0, _ := ret[0].(azure.RoleList)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetAzureADRoles indicates an expected call of GetAzureADRoles.
-func (mr *MockAzureClientMockRecorder) GetAzureADRoles(arg0, arg1, arg2 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureADRoles", reflect.TypeOf((*MockAzureClient)(nil).GetAzureADRoles), arg0, arg1, arg2)
-}
-
-// GetAzureADServicePrincipal mocks base method.
-func (m *MockAzureClient) GetAzureADServicePrincipal(arg0 context.Context, arg1 string, arg2 []string) (*azure.ServicePrincipal, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetAzureADServicePrincipal", arg0, arg1, arg2)
- ret0, _ := ret[0].(*azure.ServicePrincipal)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetAzureADServicePrincipal indicates an expected call of GetAzureADServicePrincipal.
-func (mr *MockAzureClientMockRecorder) GetAzureADServicePrincipal(arg0, arg1, arg2 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureADServicePrincipal", reflect.TypeOf((*MockAzureClient)(nil).GetAzureADServicePrincipal), arg0, arg1, arg2)
-}
-
-// GetAzureADServicePrincipalOwners mocks base method.
-func (m *MockAzureClient) GetAzureADServicePrincipalOwners(arg0 context.Context, arg1, arg2, arg3, arg4 string, arg5 []string, arg6 int32, arg7 bool) (azure.DirectoryObjectList, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetAzureADServicePrincipalOwners", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
- ret0, _ := ret[0].(azure.DirectoryObjectList)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetAzureADServicePrincipalOwners indicates an expected call of GetAzureADServicePrincipalOwners.
-func (mr *MockAzureClientMockRecorder) GetAzureADServicePrincipalOwners(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureADServicePrincipalOwners", reflect.TypeOf((*MockAzureClient)(nil).GetAzureADServicePrincipalOwners), arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
-}
-
-// GetAzureADServicePrincipals mocks base method.
-func (m *MockAzureClient) GetAzureADServicePrincipals(arg0 context.Context, arg1, arg2, arg3, arg4 string, arg5 []string, arg6 int32, arg7 bool) (azure.ServicePrincipalList, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetAzureADServicePrincipals", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
- ret0, _ := ret[0].(azure.ServicePrincipalList)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetAzureADServicePrincipals indicates an expected call of GetAzureADServicePrincipals.
-func (mr *MockAzureClientMockRecorder) GetAzureADServicePrincipals(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureADServicePrincipals", reflect.TypeOf((*MockAzureClient)(nil).GetAzureADServicePrincipals), arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
-}
-
// GetAzureADTenants mocks base method.
func (m *MockAzureClient) GetAzureADTenants(arg0 context.Context, arg1 bool) (azure.TenantList, error) {
m.ctrl.T.Helper()
@@ -273,435 +80,151 @@ func (mr *MockAzureClientMockRecorder) GetAzureADTenants(arg0, arg1 interface{})
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureADTenants", reflect.TypeOf((*MockAzureClient)(nil).GetAzureADTenants), arg0, arg1)
}
-// GetAzureADUser mocks base method.
-func (m *MockAzureClient) GetAzureADUser(arg0 context.Context, arg1 string, arg2 []string) (*azure.User, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetAzureADUser", arg0, arg1, arg2)
- ret0, _ := ret[0].(*azure.User)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetAzureADUser indicates an expected call of GetAzureADUser.
-func (mr *MockAzureClientMockRecorder) GetAzureADUser(arg0, arg1, arg2 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureADUser", reflect.TypeOf((*MockAzureClient)(nil).GetAzureADUser), arg0, arg1, arg2)
-}
-
-// GetAzureADUsers mocks base method.
-func (m *MockAzureClient) GetAzureADUsers(arg0 context.Context, arg1, arg2, arg3 string, arg4 []string, arg5 int32, arg6 bool) (azure.UserList, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetAzureADUsers", arg0, arg1, arg2, arg3, arg4, arg5, arg6)
- ret0, _ := ret[0].(azure.UserList)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetAzureADUsers indicates an expected call of GetAzureADUsers.
-func (mr *MockAzureClientMockRecorder) GetAzureADUsers(arg0, arg1, arg2, arg3, arg4, arg5, arg6 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureADUsers", reflect.TypeOf((*MockAzureClient)(nil).GetAzureADUsers), arg0, arg1, arg2, arg3, arg4, arg5, arg6)
-}
-
-// GetAzureDevice mocks base method.
-func (m *MockAzureClient) GetAzureDevice(arg0 context.Context, arg1 string, arg2 []string) (*azure.Device, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetAzureDevice", arg0, arg1, arg2)
- ret0, _ := ret[0].(*azure.Device)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetAzureDevice indicates an expected call of GetAzureDevice.
-func (mr *MockAzureClientMockRecorder) GetAzureDevice(arg0, arg1, arg2 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureDevice", reflect.TypeOf((*MockAzureClient)(nil).GetAzureDevice), arg0, arg1, arg2)
-}
-
-// GetAzureDevices mocks base method.
-func (m *MockAzureClient) GetAzureDevices(arg0 context.Context, arg1, arg2, arg3, arg4 string, arg5 []string, arg6 int32, arg7 bool) (azure.DeviceList, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetAzureDevices", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
- ret0, _ := ret[0].(azure.DeviceList)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetAzureDevices indicates an expected call of GetAzureDevices.
-func (mr *MockAzureClientMockRecorder) GetAzureDevices(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureDevices", reflect.TypeOf((*MockAzureClient)(nil).GetAzureDevices), arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
-}
-
-// GetAzureKeyVault mocks base method.
-func (m *MockAzureClient) GetAzureKeyVault(arg0 context.Context, arg1, arg2, arg3 string) (*azure.KeyVault, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetAzureKeyVault", arg0, arg1, arg2, arg3)
- ret0, _ := ret[0].(*azure.KeyVault)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetAzureKeyVault indicates an expected call of GetAzureKeyVault.
-func (mr *MockAzureClientMockRecorder) GetAzureKeyVault(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureKeyVault", reflect.TypeOf((*MockAzureClient)(nil).GetAzureKeyVault), arg0, arg1, arg2, arg3)
-}
-
-// GetAzureKeyVaults mocks base method.
-func (m *MockAzureClient) GetAzureKeyVaults(arg0 context.Context, arg1 string, arg2 int32) (azure.KeyVaultList, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetAzureKeyVaults", arg0, arg1, arg2)
- ret0, _ := ret[0].(azure.KeyVaultList)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetAzureKeyVaults indicates an expected call of GetAzureKeyVaults.
-func (mr *MockAzureClientMockRecorder) GetAzureKeyVaults(arg0, arg1, arg2 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureKeyVaults", reflect.TypeOf((*MockAzureClient)(nil).GetAzureKeyVaults), arg0, arg1, arg2)
-}
-
-// GetAzureManagementGroup mocks base method.
-func (m *MockAzureClient) GetAzureManagementGroup(arg0 context.Context, arg1, arg2, arg3 string, arg4 bool) (*azure.ManagementGroup, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetAzureManagementGroup", arg0, arg1, arg2, arg3, arg4)
- ret0, _ := ret[0].(*azure.ManagementGroup)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetAzureManagementGroup indicates an expected call of GetAzureManagementGroup.
-func (mr *MockAzureClientMockRecorder) GetAzureManagementGroup(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureManagementGroup", reflect.TypeOf((*MockAzureClient)(nil).GetAzureManagementGroup), arg0, arg1, arg2, arg3, arg4)
-}
-
-// GetAzureManagementGroups mocks base method.
-func (m *MockAzureClient) GetAzureManagementGroups(arg0 context.Context) (azure.ManagementGroupList, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetAzureManagementGroups", arg0)
- ret0, _ := ret[0].(azure.ManagementGroupList)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetAzureManagementGroups indicates an expected call of GetAzureManagementGroups.
-func (mr *MockAzureClientMockRecorder) GetAzureManagementGroups(arg0 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureManagementGroups", reflect.TypeOf((*MockAzureClient)(nil).GetAzureManagementGroups), arg0)
-}
-
-// GetAzureResourceGroup mocks base method.
-func (m *MockAzureClient) GetAzureResourceGroup(arg0 context.Context, arg1, arg2 string) (*azure.ResourceGroup, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetAzureResourceGroup", arg0, arg1, arg2)
- ret0, _ := ret[0].(*azure.ResourceGroup)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetAzureResourceGroup indicates an expected call of GetAzureResourceGroup.
-func (mr *MockAzureClientMockRecorder) GetAzureResourceGroup(arg0, arg1, arg2 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureResourceGroup", reflect.TypeOf((*MockAzureClient)(nil).GetAzureResourceGroup), arg0, arg1, arg2)
-}
-
-// GetAzureResourceGroups mocks base method.
-func (m *MockAzureClient) GetAzureResourceGroups(arg0 context.Context, arg1, arg2 string, arg3 int32) (azure.ResourceGroupList, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetAzureResourceGroups", arg0, arg1, arg2, arg3)
- ret0, _ := ret[0].(azure.ResourceGroupList)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetAzureResourceGroups indicates an expected call of GetAzureResourceGroups.
-func (mr *MockAzureClientMockRecorder) GetAzureResourceGroups(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureResourceGroups", reflect.TypeOf((*MockAzureClient)(nil).GetAzureResourceGroups), arg0, arg1, arg2, arg3)
-}
-
-// GetAzureStorageAccount mocks base method.
-func (m *MockAzureClient) GetAzureStorageAccount(arg0 context.Context, arg1, arg2, arg3, arg4 string) (*azure.StorageAccount, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetAzureStorageAccount", arg0, arg1, arg2, arg3, arg4)
- ret0, _ := ret[0].(*azure.StorageAccount)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetAzureStorageAccount indicates an expected call of GetAzureStorageAccount.
-func (mr *MockAzureClientMockRecorder) GetAzureStorageAccount(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureStorageAccount", reflect.TypeOf((*MockAzureClient)(nil).GetAzureStorageAccount), arg0, arg1, arg2, arg3, arg4)
-}
-
-// GetAzureStorageAccounts mocks base method.
-func (m *MockAzureClient) GetAzureStorageAccounts(arg0 context.Context, arg1 string) (azure.StorageAccountList, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetAzureStorageAccounts", arg0, arg1)
- ret0, _ := ret[0].(azure.StorageAccountList)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetAzureStorageAccounts indicates an expected call of GetAzureStorageAccounts.
-func (mr *MockAzureClientMockRecorder) GetAzureStorageAccounts(arg0, arg1 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureStorageAccounts", reflect.TypeOf((*MockAzureClient)(nil).GetAzureStorageAccounts), arg0, arg1)
-}
-
-// GetAzureSubscription mocks base method.
-func (m *MockAzureClient) GetAzureSubscription(arg0 context.Context, arg1 string) (*azure.Subscription, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetAzureSubscription", arg0, arg1)
- ret0, _ := ret[0].(*azure.Subscription)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetAzureSubscription indicates an expected call of GetAzureSubscription.
-func (mr *MockAzureClientMockRecorder) GetAzureSubscription(arg0, arg1 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureSubscription", reflect.TypeOf((*MockAzureClient)(nil).GetAzureSubscription), arg0, arg1)
-}
-
-// GetAzureSubscriptions mocks base method.
-func (m *MockAzureClient) GetAzureSubscriptions(arg0 context.Context) (azure.SubscriptionList, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetAzureSubscriptions", arg0)
- ret0, _ := ret[0].(azure.SubscriptionList)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetAzureSubscriptions indicates an expected call of GetAzureSubscriptions.
-func (mr *MockAzureClientMockRecorder) GetAzureSubscriptions(arg0 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureSubscriptions", reflect.TypeOf((*MockAzureClient)(nil).GetAzureSubscriptions), arg0)
-}
-
-// GetAzureVirtualMachine mocks base method.
-func (m *MockAzureClient) GetAzureVirtualMachine(arg0 context.Context, arg1, arg2, arg3, arg4 string) (*azure.VirtualMachine, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetAzureVirtualMachine", arg0, arg1, arg2, arg3, arg4)
- ret0, _ := ret[0].(*azure.VirtualMachine)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetAzureVirtualMachine indicates an expected call of GetAzureVirtualMachine.
-func (mr *MockAzureClientMockRecorder) GetAzureVirtualMachine(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureVirtualMachine", reflect.TypeOf((*MockAzureClient)(nil).GetAzureVirtualMachine), arg0, arg1, arg2, arg3, arg4)
-}
-
-// GetAzureVirtualMachines mocks base method.
-func (m *MockAzureClient) GetAzureVirtualMachines(arg0 context.Context, arg1 string, arg2 bool) (azure.VirtualMachineList, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetAzureVirtualMachines", arg0, arg1, arg2)
- ret0, _ := ret[0].(azure.VirtualMachineList)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetAzureVirtualMachines indicates an expected call of GetAzureVirtualMachines.
-func (mr *MockAzureClientMockRecorder) GetAzureVirtualMachines(arg0, arg1, arg2 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureVirtualMachines", reflect.TypeOf((*MockAzureClient)(nil).GetAzureVirtualMachines), arg0, arg1, arg2)
-}
-
-// GetResourceRoleAssignments mocks base method.
-func (m *MockAzureClient) GetResourceRoleAssignments(arg0 context.Context, arg1, arg2, arg3 string) (azure.RoleAssignmentList, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetResourceRoleAssignments", arg0, arg1, arg2, arg3)
- ret0, _ := ret[0].(azure.RoleAssignmentList)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetResourceRoleAssignments indicates an expected call of GetResourceRoleAssignments.
-func (mr *MockAzureClientMockRecorder) GetResourceRoleAssignments(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetResourceRoleAssignments", reflect.TypeOf((*MockAzureClient)(nil).GetResourceRoleAssignments), arg0, arg1, arg2, arg3)
-}
-
-// GetRoleAssignmentsForResource mocks base method.
-func (m *MockAzureClient) GetRoleAssignmentsForResource(arg0 context.Context, arg1, arg2 string) (azure.RoleAssignmentList, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetRoleAssignmentsForResource", arg0, arg1, arg2)
- ret0, _ := ret[0].(azure.RoleAssignmentList)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetRoleAssignmentsForResource indicates an expected call of GetRoleAssignmentsForResource.
-func (mr *MockAzureClientMockRecorder) GetRoleAssignmentsForResource(arg0, arg1, arg2 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRoleAssignmentsForResource", reflect.TypeOf((*MockAzureClient)(nil).GetRoleAssignmentsForResource), arg0, arg1, arg2)
-}
-
-// ListAzureADAppMemberObjects mocks base method.
-func (m *MockAzureClient) ListAzureADAppMemberObjects(arg0 context.Context, arg1 string, arg2 bool) <-chan azure.MemberObjectResult {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ListAzureADAppMemberObjects", arg0, arg1, arg2)
- ret0, _ := ret[0].(<-chan azure.MemberObjectResult)
- return ret0
-}
-
-// ListAzureADAppMemberObjects indicates an expected call of ListAzureADAppMemberObjects.
-func (mr *MockAzureClientMockRecorder) ListAzureADAppMemberObjects(arg0, arg1, arg2 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureADAppMemberObjects", reflect.TypeOf((*MockAzureClient)(nil).ListAzureADAppMemberObjects), arg0, arg1, arg2)
-}
-
// ListAzureADAppOwners mocks base method.
-func (m *MockAzureClient) ListAzureADAppOwners(arg0 context.Context, arg1, arg2, arg3, arg4 string, arg5 []string) <-chan azure.AppOwnerResult {
+func (m *MockAzureClient) ListAzureADAppOwners(arg0 context.Context, arg1 string, arg2 query.GraphParams) <-chan client.AzureResult[json.RawMessage] {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ListAzureADAppOwners", arg0, arg1, arg2, arg3, arg4, arg5)
- ret0, _ := ret[0].(<-chan azure.AppOwnerResult)
+ ret := m.ctrl.Call(m, "ListAzureADAppOwners", arg0, arg1, arg2)
+ ret0, _ := ret[0].(<-chan client.AzureResult[json.RawMessage])
return ret0
}
// ListAzureADAppOwners indicates an expected call of ListAzureADAppOwners.
-func (mr *MockAzureClientMockRecorder) ListAzureADAppOwners(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call {
+func (mr *MockAzureClientMockRecorder) ListAzureADAppOwners(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureADAppOwners", reflect.TypeOf((*MockAzureClient)(nil).ListAzureADAppOwners), arg0, arg1, arg2, arg3, arg4, arg5)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureADAppOwners", reflect.TypeOf((*MockAzureClient)(nil).ListAzureADAppOwners), arg0, arg1, arg2)
}
// ListAzureADAppRoleAssignments mocks base method.
-func (m *MockAzureClient) ListAzureADAppRoleAssignments(arg0 context.Context, arg1, arg2, arg3, arg4, arg5 string, arg6 []string) <-chan azure.AppRoleAssignmentResult {
+func (m *MockAzureClient) ListAzureADAppRoleAssignments(arg0 context.Context, arg1 string, arg2 query.GraphParams) <-chan client.AzureResult[azure.AppRoleAssignment] {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ListAzureADAppRoleAssignments", arg0, arg1, arg2, arg3, arg4, arg5, arg6)
- ret0, _ := ret[0].(<-chan azure.AppRoleAssignmentResult)
+ ret := m.ctrl.Call(m, "ListAzureADAppRoleAssignments", arg0, arg1, arg2)
+ ret0, _ := ret[0].(<-chan client.AzureResult[azure.AppRoleAssignment])
return ret0
}
// ListAzureADAppRoleAssignments indicates an expected call of ListAzureADAppRoleAssignments.
-func (mr *MockAzureClientMockRecorder) ListAzureADAppRoleAssignments(arg0, arg1, arg2, arg3, arg4, arg5, arg6 interface{}) *gomock.Call {
+func (mr *MockAzureClientMockRecorder) ListAzureADAppRoleAssignments(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureADAppRoleAssignments", reflect.TypeOf((*MockAzureClient)(nil).ListAzureADAppRoleAssignments), arg0, arg1, arg2, arg3, arg4, arg5, arg6)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureADAppRoleAssignments", reflect.TypeOf((*MockAzureClient)(nil).ListAzureADAppRoleAssignments), arg0, arg1, arg2)
}
// ListAzureADApps mocks base method.
-func (m *MockAzureClient) ListAzureADApps(arg0 context.Context, arg1, arg2, arg3, arg4 string, arg5 []string) <-chan azure.ApplicationResult {
+func (m *MockAzureClient) ListAzureADApps(arg0 context.Context, arg1 query.GraphParams) <-chan client.AzureResult[azure.Application] {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ListAzureADApps", arg0, arg1, arg2, arg3, arg4, arg5)
- ret0, _ := ret[0].(<-chan azure.ApplicationResult)
+ ret := m.ctrl.Call(m, "ListAzureADApps", arg0, arg1)
+ ret0, _ := ret[0].(<-chan client.AzureResult[azure.Application])
return ret0
}
// ListAzureADApps indicates an expected call of ListAzureADApps.
-func (mr *MockAzureClientMockRecorder) ListAzureADApps(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call {
+func (mr *MockAzureClientMockRecorder) ListAzureADApps(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureADApps", reflect.TypeOf((*MockAzureClient)(nil).ListAzureADApps), arg0, arg1, arg2, arg3, arg4, arg5)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureADApps", reflect.TypeOf((*MockAzureClient)(nil).ListAzureADApps), arg0, arg1)
}
// ListAzureADGroupMembers mocks base method.
-func (m *MockAzureClient) ListAzureADGroupMembers(arg0 context.Context, arg1, arg2, arg3, arg4 string, arg5 []string) <-chan azure.MemberObjectResult {
+func (m *MockAzureClient) ListAzureADGroupMembers(arg0 context.Context, arg1 string, arg2 query.GraphParams) <-chan client.AzureResult[json.RawMessage] {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ListAzureADGroupMembers", arg0, arg1, arg2, arg3, arg4, arg5)
- ret0, _ := ret[0].(<-chan azure.MemberObjectResult)
+ ret := m.ctrl.Call(m, "ListAzureADGroupMembers", arg0, arg1, arg2)
+ ret0, _ := ret[0].(<-chan client.AzureResult[json.RawMessage])
return ret0
}
// ListAzureADGroupMembers indicates an expected call of ListAzureADGroupMembers.
-func (mr *MockAzureClientMockRecorder) ListAzureADGroupMembers(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call {
+func (mr *MockAzureClientMockRecorder) ListAzureADGroupMembers(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureADGroupMembers", reflect.TypeOf((*MockAzureClient)(nil).ListAzureADGroupMembers), arg0, arg1, arg2, arg3, arg4, arg5)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureADGroupMembers", reflect.TypeOf((*MockAzureClient)(nil).ListAzureADGroupMembers), arg0, arg1, arg2)
}
// ListAzureADGroupOwners mocks base method.
-func (m *MockAzureClient) ListAzureADGroupOwners(arg0 context.Context, arg1, arg2, arg3, arg4 string, arg5 []string) <-chan azure.GroupOwnerResult {
+func (m *MockAzureClient) ListAzureADGroupOwners(arg0 context.Context, arg1 string, arg2 query.GraphParams) <-chan client.AzureResult[json.RawMessage] {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ListAzureADGroupOwners", arg0, arg1, arg2, arg3, arg4, arg5)
- ret0, _ := ret[0].(<-chan azure.GroupOwnerResult)
+ ret := m.ctrl.Call(m, "ListAzureADGroupOwners", arg0, arg1, arg2)
+ ret0, _ := ret[0].(<-chan client.AzureResult[json.RawMessage])
return ret0
}
// ListAzureADGroupOwners indicates an expected call of ListAzureADGroupOwners.
-func (mr *MockAzureClientMockRecorder) ListAzureADGroupOwners(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call {
+func (mr *MockAzureClientMockRecorder) ListAzureADGroupOwners(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureADGroupOwners", reflect.TypeOf((*MockAzureClient)(nil).ListAzureADGroupOwners), arg0, arg1, arg2, arg3, arg4, arg5)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureADGroupOwners", reflect.TypeOf((*MockAzureClient)(nil).ListAzureADGroupOwners), arg0, arg1, arg2)
}
// ListAzureADGroups mocks base method.
-func (m *MockAzureClient) ListAzureADGroups(arg0 context.Context, arg1, arg2, arg3, arg4 string, arg5 []string) <-chan azure.GroupResult {
+func (m *MockAzureClient) ListAzureADGroups(arg0 context.Context, arg1 query.GraphParams) <-chan client.AzureResult[azure.Group] {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ListAzureADGroups", arg0, arg1, arg2, arg3, arg4, arg5)
- ret0, _ := ret[0].(<-chan azure.GroupResult)
+ ret := m.ctrl.Call(m, "ListAzureADGroups", arg0, arg1)
+ ret0, _ := ret[0].(<-chan client.AzureResult[azure.Group])
return ret0
}
// ListAzureADGroups indicates an expected call of ListAzureADGroups.
-func (mr *MockAzureClientMockRecorder) ListAzureADGroups(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call {
+func (mr *MockAzureClientMockRecorder) ListAzureADGroups(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureADGroups", reflect.TypeOf((*MockAzureClient)(nil).ListAzureADGroups), arg0, arg1, arg2, arg3, arg4, arg5)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureADGroups", reflect.TypeOf((*MockAzureClient)(nil).ListAzureADGroups), arg0, arg1)
}
// ListAzureADRoleAssignments mocks base method.
-func (m *MockAzureClient) ListAzureADRoleAssignments(arg0 context.Context, arg1, arg2, arg3, arg4 string, arg5 []string) <-chan azure.UnifiedRoleAssignmentResult {
+func (m *MockAzureClient) ListAzureADRoleAssignments(arg0 context.Context, arg1 query.GraphParams) <-chan client.AzureResult[azure.UnifiedRoleAssignment] {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ListAzureADRoleAssignments", arg0, arg1, arg2, arg3, arg4, arg5)
- ret0, _ := ret[0].(<-chan azure.UnifiedRoleAssignmentResult)
+ ret := m.ctrl.Call(m, "ListAzureADRoleAssignments", arg0, arg1)
+ ret0, _ := ret[0].(<-chan client.AzureResult[azure.UnifiedRoleAssignment])
return ret0
}
// ListAzureADRoleAssignments indicates an expected call of ListAzureADRoleAssignments.
-func (mr *MockAzureClientMockRecorder) ListAzureADRoleAssignments(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call {
+func (mr *MockAzureClientMockRecorder) ListAzureADRoleAssignments(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureADRoleAssignments", reflect.TypeOf((*MockAzureClient)(nil).ListAzureADRoleAssignments), arg0, arg1, arg2, arg3, arg4, arg5)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureADRoleAssignments", reflect.TypeOf((*MockAzureClient)(nil).ListAzureADRoleAssignments), arg0, arg1)
}
// ListAzureADRoles mocks base method.
-func (m *MockAzureClient) ListAzureADRoles(arg0 context.Context, arg1, arg2 string) <-chan azure.RoleResult {
+func (m *MockAzureClient) ListAzureADRoles(arg0 context.Context, arg1 query.GraphParams) <-chan client.AzureResult[azure.Role] {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ListAzureADRoles", arg0, arg1, arg2)
- ret0, _ := ret[0].(<-chan azure.RoleResult)
+ ret := m.ctrl.Call(m, "ListAzureADRoles", arg0, arg1)
+ ret0, _ := ret[0].(<-chan client.AzureResult[azure.Role])
return ret0
}
// ListAzureADRoles indicates an expected call of ListAzureADRoles.
-func (mr *MockAzureClientMockRecorder) ListAzureADRoles(arg0, arg1, arg2 interface{}) *gomock.Call {
+func (mr *MockAzureClientMockRecorder) ListAzureADRoles(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureADRoles", reflect.TypeOf((*MockAzureClient)(nil).ListAzureADRoles), arg0, arg1, arg2)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureADRoles", reflect.TypeOf((*MockAzureClient)(nil).ListAzureADRoles), arg0, arg1)
}
// ListAzureADServicePrincipalOwners mocks base method.
-func (m *MockAzureClient) ListAzureADServicePrincipalOwners(arg0 context.Context, arg1, arg2, arg3, arg4 string, arg5 []string) <-chan azure.ServicePrincipalOwnerResult {
+func (m *MockAzureClient) ListAzureADServicePrincipalOwners(arg0 context.Context, arg1 string, arg2 query.GraphParams) <-chan client.AzureResult[json.RawMessage] {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ListAzureADServicePrincipalOwners", arg0, arg1, arg2, arg3, arg4, arg5)
- ret0, _ := ret[0].(<-chan azure.ServicePrincipalOwnerResult)
+ ret := m.ctrl.Call(m, "ListAzureADServicePrincipalOwners", arg0, arg1, arg2)
+ ret0, _ := ret[0].(<-chan client.AzureResult[json.RawMessage])
return ret0
}
// ListAzureADServicePrincipalOwners indicates an expected call of ListAzureADServicePrincipalOwners.
-func (mr *MockAzureClientMockRecorder) ListAzureADServicePrincipalOwners(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call {
+func (mr *MockAzureClientMockRecorder) ListAzureADServicePrincipalOwners(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureADServicePrincipalOwners", reflect.TypeOf((*MockAzureClient)(nil).ListAzureADServicePrincipalOwners), arg0, arg1, arg2, arg3, arg4, arg5)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureADServicePrincipalOwners", reflect.TypeOf((*MockAzureClient)(nil).ListAzureADServicePrincipalOwners), arg0, arg1, arg2)
}
// ListAzureADServicePrincipals mocks base method.
-func (m *MockAzureClient) ListAzureADServicePrincipals(arg0 context.Context, arg1, arg2, arg3, arg4 string, arg5 []string) <-chan azure.ServicePrincipalResult {
+func (m *MockAzureClient) ListAzureADServicePrincipals(arg0 context.Context, arg1 query.GraphParams) <-chan client.AzureResult[azure.ServicePrincipal] {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ListAzureADServicePrincipals", arg0, arg1, arg2, arg3, arg4, arg5)
- ret0, _ := ret[0].(<-chan azure.ServicePrincipalResult)
+ ret := m.ctrl.Call(m, "ListAzureADServicePrincipals", arg0, arg1)
+ ret0, _ := ret[0].(<-chan client.AzureResult[azure.ServicePrincipal])
return ret0
}
// ListAzureADServicePrincipals indicates an expected call of ListAzureADServicePrincipals.
-func (mr *MockAzureClientMockRecorder) ListAzureADServicePrincipals(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call {
+func (mr *MockAzureClientMockRecorder) ListAzureADServicePrincipals(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureADServicePrincipals", reflect.TypeOf((*MockAzureClient)(nil).ListAzureADServicePrincipals), arg0, arg1, arg2, arg3, arg4, arg5)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureADServicePrincipals", reflect.TypeOf((*MockAzureClient)(nil).ListAzureADServicePrincipals), arg0, arg1)
}
// ListAzureADTenants mocks base method.
-func (m *MockAzureClient) ListAzureADTenants(arg0 context.Context, arg1 bool) <-chan azure.TenantResult {
+func (m *MockAzureClient) ListAzureADTenants(arg0 context.Context, arg1 bool) <-chan client.AzureResult[azure.Tenant] {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ListAzureADTenants", arg0, arg1)
- ret0, _ := ret[0].(<-chan azure.TenantResult)
+ ret0, _ := ret[0].(<-chan client.AzureResult[azure.Tenant])
return ret0
}
@@ -712,24 +235,24 @@ func (mr *MockAzureClientMockRecorder) ListAzureADTenants(arg0, arg1 interface{}
}
// ListAzureADUsers mocks base method.
-func (m *MockAzureClient) ListAzureADUsers(arg0 context.Context, arg1, arg2, arg3 string, arg4 []string) <-chan azure.UserResult {
+func (m *MockAzureClient) ListAzureADUsers(arg0 context.Context, arg1 query.GraphParams) <-chan client.AzureResult[azure.User] {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ListAzureADUsers", arg0, arg1, arg2, arg3, arg4)
- ret0, _ := ret[0].(<-chan azure.UserResult)
+ ret := m.ctrl.Call(m, "ListAzureADUsers", arg0, arg1)
+ ret0, _ := ret[0].(<-chan client.AzureResult[azure.User])
return ret0
}
// ListAzureADUsers indicates an expected call of ListAzureADUsers.
-func (mr *MockAzureClientMockRecorder) ListAzureADUsers(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
+func (mr *MockAzureClientMockRecorder) ListAzureADUsers(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureADUsers", reflect.TypeOf((*MockAzureClient)(nil).ListAzureADUsers), arg0, arg1, arg2, arg3, arg4)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureADUsers", reflect.TypeOf((*MockAzureClient)(nil).ListAzureADUsers), arg0, arg1)
}
// ListAzureAutomationAccounts mocks base method.
-func (m *MockAzureClient) ListAzureAutomationAccounts(arg0 context.Context, arg1 string) <-chan azure.AutomationAccountResult {
+func (m *MockAzureClient) ListAzureAutomationAccounts(arg0 context.Context, arg1 string) <-chan client.AzureResult[azure.AutomationAccount] {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ListAzureAutomationAccounts", arg0, arg1)
- ret0, _ := ret[0].(<-chan azure.AutomationAccountResult)
+ ret0, _ := ret[0].(<-chan client.AzureResult[azure.AutomationAccount])
return ret0
}
@@ -740,10 +263,10 @@ func (mr *MockAzureClientMockRecorder) ListAzureAutomationAccounts(arg0, arg1 in
}
// ListAzureContainerRegistries mocks base method.
-func (m *MockAzureClient) ListAzureContainerRegistries(arg0 context.Context, arg1 string) <-chan azure.ContainerRegistryResult {
+func (m *MockAzureClient) ListAzureContainerRegistries(arg0 context.Context, arg1 string) <-chan client.AzureResult[azure.ContainerRegistry] {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ListAzureContainerRegistries", arg0, arg1)
- ret0, _ := ret[0].(<-chan azure.ContainerRegistryResult)
+ ret0, _ := ret[0].(<-chan client.AzureResult[azure.ContainerRegistry])
return ret0
}
@@ -754,10 +277,10 @@ func (mr *MockAzureClientMockRecorder) ListAzureContainerRegistries(arg0, arg1 i
}
// ListAzureDeviceRegisteredOwners mocks base method.
-func (m *MockAzureClient) ListAzureDeviceRegisteredOwners(arg0 context.Context, arg1 string, arg2 bool) <-chan azure.DeviceRegisteredOwnerResult {
+func (m *MockAzureClient) ListAzureDeviceRegisteredOwners(arg0 context.Context, arg1 string, arg2 query.GraphParams) <-chan client.AzureResult[json.RawMessage] {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ListAzureDeviceRegisteredOwners", arg0, arg1, arg2)
- ret0, _ := ret[0].(<-chan azure.DeviceRegisteredOwnerResult)
+ ret0, _ := ret[0].(<-chan client.AzureResult[json.RawMessage])
return ret0
}
@@ -768,24 +291,24 @@ func (mr *MockAzureClientMockRecorder) ListAzureDeviceRegisteredOwners(arg0, arg
}
// ListAzureDevices mocks base method.
-func (m *MockAzureClient) ListAzureDevices(arg0 context.Context, arg1, arg2, arg3, arg4 string, arg5 []string) <-chan azure.DeviceResult {
+func (m *MockAzureClient) ListAzureDevices(arg0 context.Context, arg1 query.GraphParams) <-chan client.AzureResult[azure.Device] {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ListAzureDevices", arg0, arg1, arg2, arg3, arg4, arg5)
- ret0, _ := ret[0].(<-chan azure.DeviceResult)
+ ret := m.ctrl.Call(m, "ListAzureDevices", arg0, arg1)
+ ret0, _ := ret[0].(<-chan client.AzureResult[azure.Device])
return ret0
}
// ListAzureDevices indicates an expected call of ListAzureDevices.
-func (mr *MockAzureClientMockRecorder) ListAzureDevices(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call {
+func (mr *MockAzureClientMockRecorder) ListAzureDevices(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureDevices", reflect.TypeOf((*MockAzureClient)(nil).ListAzureDevices), arg0, arg1, arg2, arg3, arg4, arg5)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureDevices", reflect.TypeOf((*MockAzureClient)(nil).ListAzureDevices), arg0, arg1)
}
// ListAzureFunctionApps mocks base method.
-func (m *MockAzureClient) ListAzureFunctionApps(arg0 context.Context, arg1 string) <-chan azure.FunctionAppResult {
+func (m *MockAzureClient) ListAzureFunctionApps(arg0 context.Context, arg1 string) <-chan client.AzureResult[azure.FunctionApp] {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ListAzureFunctionApps", arg0, arg1)
- ret0, _ := ret[0].(<-chan azure.FunctionAppResult)
+ ret0, _ := ret[0].(<-chan client.AzureResult[azure.FunctionApp])
return ret0
}
@@ -796,10 +319,10 @@ func (mr *MockAzureClientMockRecorder) ListAzureFunctionApps(arg0, arg1 interfac
}
// ListAzureKeyVaults mocks base method.
-func (m *MockAzureClient) ListAzureKeyVaults(arg0 context.Context, arg1 string, arg2 int32) <-chan azure.KeyVaultResult {
+func (m *MockAzureClient) ListAzureKeyVaults(arg0 context.Context, arg1 string, arg2 query.RMParams) <-chan client.AzureResult[azure.KeyVault] {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ListAzureKeyVaults", arg0, arg1, arg2)
- ret0, _ := ret[0].(<-chan azure.KeyVaultResult)
+ ret0, _ := ret[0].(<-chan client.AzureResult[azure.KeyVault])
return ret0
}
@@ -810,10 +333,10 @@ func (mr *MockAzureClientMockRecorder) ListAzureKeyVaults(arg0, arg1, arg2 inter
}
// ListAzureLogicApps mocks base method.
-func (m *MockAzureClient) ListAzureLogicApps(arg0 context.Context, arg1, arg2 string, arg3 int32) <-chan azure.LogicAppResult {
+func (m *MockAzureClient) ListAzureLogicApps(arg0 context.Context, arg1, arg2 string, arg3 int32) <-chan client.AzureResult[azure.LogicApp] {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ListAzureLogicApps", arg0, arg1, arg2, arg3)
- ret0, _ := ret[0].(<-chan azure.LogicAppResult)
+ ret0, _ := ret[0].(<-chan client.AzureResult[azure.LogicApp])
return ret0
}
@@ -824,52 +347,52 @@ func (mr *MockAzureClientMockRecorder) ListAzureLogicApps(arg0, arg1, arg2, arg3
}
// ListAzureManagedClusters mocks base method.
-func (m *MockAzureClient) ListAzureManagedClusters(arg0 context.Context, arg1 string, arg2 bool) <-chan azure.ManagedClusterResult {
+func (m *MockAzureClient) ListAzureManagedClusters(arg0 context.Context, arg1 string) <-chan client.AzureResult[azure.ManagedCluster] {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ListAzureManagedClusters", arg0, arg1, arg2)
- ret0, _ := ret[0].(<-chan azure.ManagedClusterResult)
+ ret := m.ctrl.Call(m, "ListAzureManagedClusters", arg0, arg1)
+ ret0, _ := ret[0].(<-chan client.AzureResult[azure.ManagedCluster])
return ret0
}
// ListAzureManagedClusters indicates an expected call of ListAzureManagedClusters.
-func (mr *MockAzureClientMockRecorder) ListAzureManagedClusters(arg0, arg1, arg2 interface{}) *gomock.Call {
+func (mr *MockAzureClientMockRecorder) ListAzureManagedClusters(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureManagedClusters", reflect.TypeOf((*MockAzureClient)(nil).ListAzureManagedClusters), arg0, arg1, arg2)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureManagedClusters", reflect.TypeOf((*MockAzureClient)(nil).ListAzureManagedClusters), arg0, arg1)
}
// ListAzureManagementGroupDescendants mocks base method.
-func (m *MockAzureClient) ListAzureManagementGroupDescendants(arg0 context.Context, arg1 string) <-chan azure.DescendantInfoResult {
+func (m *MockAzureClient) ListAzureManagementGroupDescendants(arg0 context.Context, arg1 string, arg2 int32) <-chan client.AzureResult[azure.DescendantInfo] {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ListAzureManagementGroupDescendants", arg0, arg1)
- ret0, _ := ret[0].(<-chan azure.DescendantInfoResult)
+ ret := m.ctrl.Call(m, "ListAzureManagementGroupDescendants", arg0, arg1, arg2)
+ ret0, _ := ret[0].(<-chan client.AzureResult[azure.DescendantInfo])
return ret0
}
// ListAzureManagementGroupDescendants indicates an expected call of ListAzureManagementGroupDescendants.
-func (mr *MockAzureClientMockRecorder) ListAzureManagementGroupDescendants(arg0, arg1 interface{}) *gomock.Call {
+func (mr *MockAzureClientMockRecorder) ListAzureManagementGroupDescendants(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureManagementGroupDescendants", reflect.TypeOf((*MockAzureClient)(nil).ListAzureManagementGroupDescendants), arg0, arg1)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureManagementGroupDescendants", reflect.TypeOf((*MockAzureClient)(nil).ListAzureManagementGroupDescendants), arg0, arg1, arg2)
}
// ListAzureManagementGroups mocks base method.
-func (m *MockAzureClient) ListAzureManagementGroups(arg0 context.Context) <-chan azure.ManagementGroupResult {
+func (m *MockAzureClient) ListAzureManagementGroups(arg0 context.Context, arg1 string) <-chan client.AzureResult[azure.ManagementGroup] {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ListAzureManagementGroups", arg0)
- ret0, _ := ret[0].(<-chan azure.ManagementGroupResult)
+ ret := m.ctrl.Call(m, "ListAzureManagementGroups", arg0, arg1)
+ ret0, _ := ret[0].(<-chan client.AzureResult[azure.ManagementGroup])
return ret0
}
// ListAzureManagementGroups indicates an expected call of ListAzureManagementGroups.
-func (mr *MockAzureClientMockRecorder) ListAzureManagementGroups(arg0 interface{}) *gomock.Call {
+func (mr *MockAzureClientMockRecorder) ListAzureManagementGroups(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureManagementGroups", reflect.TypeOf((*MockAzureClient)(nil).ListAzureManagementGroups), arg0)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureManagementGroups", reflect.TypeOf((*MockAzureClient)(nil).ListAzureManagementGroups), arg0, arg1)
}
// ListAzureResourceGroups mocks base method.
-func (m *MockAzureClient) ListAzureResourceGroups(arg0 context.Context, arg1, arg2 string) <-chan azure.ResourceGroupResult {
+func (m *MockAzureClient) ListAzureResourceGroups(arg0 context.Context, arg1 string, arg2 query.RMParams) <-chan client.AzureResult[azure.ResourceGroup] {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ListAzureResourceGroups", arg0, arg1, arg2)
- ret0, _ := ret[0].(<-chan azure.ResourceGroupResult)
+ ret0, _ := ret[0].(<-chan client.AzureResult[azure.ResourceGroup])
return ret0
}
@@ -880,10 +403,10 @@ func (mr *MockAzureClientMockRecorder) ListAzureResourceGroups(arg0, arg1, arg2
}
// ListAzureStorageAccounts mocks base method.
-func (m *MockAzureClient) ListAzureStorageAccounts(arg0 context.Context, arg1 string) <-chan azure.StorageAccountResult {
+func (m *MockAzureClient) ListAzureStorageAccounts(arg0 context.Context, arg1 string) <-chan client.AzureResult[azure.StorageAccount] {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ListAzureStorageAccounts", arg0, arg1)
- ret0, _ := ret[0].(<-chan azure.StorageAccountResult)
+ ret0, _ := ret[0].(<-chan client.AzureResult[azure.StorageAccount])
return ret0
}
@@ -894,10 +417,10 @@ func (mr *MockAzureClientMockRecorder) ListAzureStorageAccounts(arg0, arg1 inter
}
// ListAzureStorageContainers mocks base method.
-func (m *MockAzureClient) ListAzureStorageContainers(arg0 context.Context, arg1, arg2, arg3, arg4, arg5, arg6 string) <-chan azure.StorageContainerResult {
+func (m *MockAzureClient) ListAzureStorageContainers(arg0 context.Context, arg1, arg2, arg3, arg4, arg5, arg6 string) <-chan client.AzureResult[azure.StorageContainer] {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ListAzureStorageContainers", arg0, arg1, arg2, arg3, arg4, arg5, arg6)
- ret0, _ := ret[0].(<-chan azure.StorageContainerResult)
+ ret0, _ := ret[0].(<-chan client.AzureResult[azure.StorageContainer])
return ret0
}
@@ -908,10 +431,10 @@ func (mr *MockAzureClientMockRecorder) ListAzureStorageContainers(arg0, arg1, ar
}
// ListAzureSubscriptions mocks base method.
-func (m *MockAzureClient) ListAzureSubscriptions(arg0 context.Context) <-chan azure.SubscriptionResult {
+func (m *MockAzureClient) ListAzureSubscriptions(arg0 context.Context) <-chan client.AzureResult[azure.Subscription] {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ListAzureSubscriptions", arg0)
- ret0, _ := ret[0].(<-chan azure.SubscriptionResult)
+ ret0, _ := ret[0].(<-chan client.AzureResult[azure.Subscription])
return ret0
}
@@ -922,24 +445,24 @@ func (mr *MockAzureClientMockRecorder) ListAzureSubscriptions(arg0 interface{})
}
// ListAzureVMScaleSets mocks base method.
-func (m *MockAzureClient) ListAzureVMScaleSets(arg0 context.Context, arg1 string, arg2 bool) <-chan azure.VMScaleSetResult {
+func (m *MockAzureClient) ListAzureVMScaleSets(arg0 context.Context, arg1 string) <-chan client.AzureResult[azure.VMScaleSet] {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ListAzureVMScaleSets", arg0, arg1, arg2)
- ret0, _ := ret[0].(<-chan azure.VMScaleSetResult)
+ ret := m.ctrl.Call(m, "ListAzureVMScaleSets", arg0, arg1)
+ ret0, _ := ret[0].(<-chan client.AzureResult[azure.VMScaleSet])
return ret0
}
// ListAzureVMScaleSets indicates an expected call of ListAzureVMScaleSets.
-func (mr *MockAzureClientMockRecorder) ListAzureVMScaleSets(arg0, arg1, arg2 interface{}) *gomock.Call {
+func (mr *MockAzureClientMockRecorder) ListAzureVMScaleSets(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureVMScaleSets", reflect.TypeOf((*MockAzureClient)(nil).ListAzureVMScaleSets), arg0, arg1, arg2)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureVMScaleSets", reflect.TypeOf((*MockAzureClient)(nil).ListAzureVMScaleSets), arg0, arg1)
}
// ListAzureVirtualMachines mocks base method.
-func (m *MockAzureClient) ListAzureVirtualMachines(arg0 context.Context, arg1 string, arg2 bool) <-chan azure.VirtualMachineResult {
+func (m *MockAzureClient) ListAzureVirtualMachines(arg0 context.Context, arg1 string, arg2 query.RMParams) <-chan client.AzureResult[azure.VirtualMachine] {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ListAzureVirtualMachines", arg0, arg1, arg2)
- ret0, _ := ret[0].(<-chan azure.VirtualMachineResult)
+ ret0, _ := ret[0].(<-chan client.AzureResult[azure.VirtualMachine])
return ret0
}
@@ -950,10 +473,10 @@ func (mr *MockAzureClientMockRecorder) ListAzureVirtualMachines(arg0, arg1, arg2
}
// ListAzureWebApps mocks base method.
-func (m *MockAzureClient) ListAzureWebApps(arg0 context.Context, arg1 string) <-chan azure.WebAppResult {
+func (m *MockAzureClient) ListAzureWebApps(arg0 context.Context, arg1 string) <-chan client.AzureResult[azure.WebApp] {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ListAzureWebApps", arg0, arg1)
- ret0, _ := ret[0].(<-chan azure.WebAppResult)
+ ret0, _ := ret[0].(<-chan client.AzureResult[azure.WebApp])
return ret0
}
@@ -963,32 +486,18 @@ func (mr *MockAzureClientMockRecorder) ListAzureWebApps(arg0, arg1 interface{})
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAzureWebApps", reflect.TypeOf((*MockAzureClient)(nil).ListAzureWebApps), arg0, arg1)
}
-// ListResourceRoleAssignments mocks base method.
-func (m *MockAzureClient) ListResourceRoleAssignments(arg0 context.Context, arg1, arg2, arg3 string) <-chan azure.RoleAssignmentResult {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ListResourceRoleAssignments", arg0, arg1, arg2, arg3)
- ret0, _ := ret[0].(<-chan azure.RoleAssignmentResult)
- return ret0
-}
-
-// ListResourceRoleAssignments indicates an expected call of ListResourceRoleAssignments.
-func (mr *MockAzureClientMockRecorder) ListResourceRoleAssignments(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListResourceRoleAssignments", reflect.TypeOf((*MockAzureClient)(nil).ListResourceRoleAssignments), arg0, arg1, arg2, arg3)
-}
-
// ListRoleAssignmentsForResource mocks base method.
-func (m *MockAzureClient) ListRoleAssignmentsForResource(arg0 context.Context, arg1, arg2 string) <-chan azure.RoleAssignmentResult {
+func (m *MockAzureClient) ListRoleAssignmentsForResource(arg0 context.Context, arg1, arg2, arg3 string) <-chan client.AzureResult[azure.RoleAssignment] {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ListRoleAssignmentsForResource", arg0, arg1, arg2)
- ret0, _ := ret[0].(<-chan azure.RoleAssignmentResult)
+ ret := m.ctrl.Call(m, "ListRoleAssignmentsForResource", arg0, arg1, arg2, arg3)
+ ret0, _ := ret[0].(<-chan client.AzureResult[azure.RoleAssignment])
return ret0
}
// ListRoleAssignmentsForResource indicates an expected call of ListRoleAssignmentsForResource.
-func (mr *MockAzureClientMockRecorder) ListRoleAssignmentsForResource(arg0, arg1, arg2 interface{}) *gomock.Call {
+func (mr *MockAzureClientMockRecorder) ListRoleAssignmentsForResource(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListRoleAssignmentsForResource", reflect.TypeOf((*MockAzureClient)(nil).ListRoleAssignmentsForResource), arg0, arg1, arg2)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListRoleAssignmentsForResource", reflect.TypeOf((*MockAzureClient)(nil).ListRoleAssignmentsForResource), arg0, arg1, arg2, arg3)
}
// TenantInfo mocks base method.
diff --git a/client/query/params.go b/client/query/params.go
index f203ecb..3378ab5 100644
--- a/client/query/params.go
+++ b/client/query/params.go
@@ -38,38 +38,40 @@ const (
Skip string = "$skip"
SkipToken string = "$skipToken"
StatusOnly string = "StatusOnly"
+ TenantId string = "tenantId"
Top string = "$top"
)
-type Params struct {
+type Params interface {
+ AsMap() map[string]string
+ NeedsEventualConsistencyHeaderFlag() bool
+}
+
+type RMParams struct {
ApiVersion string
- Count bool
Expand string
Filter string
IncludeDeleted string
IncludeAllTenantCategories bool
MaxPageSize string
- OrderBy string
Recurse bool
- Search string
- Select []string
- Skip int
SkipToken string
StatusOnly bool
+ TenantId string // For cross-tenant request
Top int32
}
-func (s Params) AsMap() map[string]string {
+func (s RMParams) NeedsEventualConsistencyHeaderFlag() bool {
+ return false
+}
+
+func (s RMParams) AsMap() map[string]string {
params := make(map[string]string)
if s.ApiVersion != "" {
params[ApiVersion] = s.ApiVersion
}
- if s.Count {
- params[Count] = "true"
- }
-
if s.Expand != "" {
params[Expand] = s.Expand
}
@@ -82,14 +84,68 @@ func (s Params) AsMap() map[string]string {
params[IncludeAllTenantCategories] = "true"
}
- if s.OrderBy != "" {
- params[OrderBy] = s.OrderBy
- }
-
if s.Recurse {
params[Recurse] = "true"
}
+ if s.SkipToken != "" {
+ params[SkipToken] = s.SkipToken
+ }
+
+ if s.StatusOnly {
+ params[StatusOnly] = "true"
+ }
+
+ if s.TenantId != "" {
+ params[TenantId] = s.TenantId
+ }
+ if s.Top > 0 {
+ params[Top] = strconv.FormatInt(int64(s.Top), 10)
+ }
+
+ return params
+}
+
+type GraphParams struct {
+ Count bool
+ Expand string
+ Format string
+ Filter string
+ OrderBy string
+ Search string
+ Select []string
+ Skip int
+ Top int32
+ SkipToken string
+}
+
+func (s GraphParams) NeedsEventualConsistencyHeaderFlag() bool {
+ return s.Count || s.Search != "" || s.OrderBy != "" || (s.Filter != "" && s.OrderBy != "") || strings.Contains(s.Filter, "endsWith")
+}
+
+func (s GraphParams) AsMap() map[string]string {
+ params := make(map[string]string)
+
+ if s.Count {
+ params[Count] = "true"
+ }
+
+ if s.Expand != "" {
+ params[Expand] = s.Expand
+ }
+
+ if s.Format != "" {
+ params[Format] = s.Format
+ }
+
+ if s.Filter != "" {
+ params[Filter] = s.Filter
+ }
+
+ if s.OrderBy != "" {
+ params[OrderBy] = s.OrderBy
+ }
+
if s.Search != "" {
params[Search] = s.Search
}
@@ -106,10 +162,6 @@ func (s Params) AsMap() map[string]string {
params[SkipToken] = s.SkipToken
}
- if s.StatusOnly {
- params[StatusOnly] = "true"
- }
-
if s.Top > 0 {
params[Top] = strconv.FormatInt(int64(s.Top), 10)
}
diff --git a/client/resource_groups.go b/client/resource_groups.go
index c693fc4..cff4182 100644
--- a/client/resource_groups.go
+++ b/client/resource_groups.go
@@ -20,116 +20,23 @@ package client
import (
"context"
"fmt"
- "net/url"
"github.com/bloodhoundad/azurehound/v2/client/query"
- "github.com/bloodhoundad/azurehound/v2/client/rest"
"github.com/bloodhoundad/azurehound/v2/models/azure"
- "github.com/bloodhoundad/azurehound/v2/panicrecovery"
- "github.com/bloodhoundad/azurehound/v2/pipeline"
)
-func (s *azureClient) GetAzureResourceGroup(ctx context.Context, subscriptionId, groupName string) (*azure.ResourceGroup, error) {
+// ListAzureResourceGroups https://learn.microsoft.com/en-us/rest/api/resources/resource-groups/list?view=rest-resources-2021-04-01
+func (s *azureClient) ListAzureResourceGroups(ctx context.Context, subscriptionId string, params query.RMParams) <-chan AzureResult[azure.ResourceGroup] {
var (
- path = fmt.Sprintf("/subscriptions/%s/resourcegroups/%s", subscriptionId, groupName)
- params = query.Params{ApiVersion: "2021-04-01"}.AsMap()
- headers map[string]string
- response azure.ResourceGroup
- )
- if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
- return nil, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return nil, err
- } else {
- return &response, nil
- }
-}
-
-func (s *azureClient) GetAzureResourceGroups(ctx context.Context, subscriptionId string, filter string, top int32) (azure.ResourceGroupList, error) {
- var (
- path = fmt.Sprintf("/subscriptions/%s/resourcegroups", subscriptionId)
- params = query.Params{ApiVersion: "2021-04-01", Filter: filter, Top: top}.AsMap()
- headers map[string]string
- response azure.ResourceGroupList
+ out = make(chan AzureResult[azure.ResourceGroup])
+ path = fmt.Sprintf("/subscriptions/%s/resourcegroups", subscriptionId)
)
- if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
- return response, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return response, err
- } else {
- return response, nil
+ if params.ApiVersion == "" {
+ params.ApiVersion = "2021-04-01"
}
-}
-
-func (s *azureClient) ListAzureResourceGroups(ctx context.Context, subscriptionId, filter string) <-chan azure.ResourceGroupResult {
- out := make(chan azure.ResourceGroupResult)
-
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
-
- var (
- objectId = fmt.Sprintf("/subscriptions/%s", subscriptionId)
- errResult = azure.ResourceGroupResult{SubscriptionId: objectId}
- nextLink string
- )
- if result, err := s.GetAzureResourceGroups(ctx, subscriptionId, filter, 1000); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range result.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.ResourceGroupResult{
- SubscriptionId: objectId,
- Ok: u,
- }); !ok {
- return
- }
- }
+ go getAzureObjectList[azure.ResourceGroup](s.resourceManager, ctx, path, params, out)
- nextLink = result.NextLink
- for nextLink != "" {
- var list azure.ResourceGroupList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if res, err := s.resourceManager.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if err := rest.Decode(res.Body, &list); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.ResourceGroupResult{
- SubscriptionId: objectId,
- Ok: u,
- }); !ok {
- return
- }
- }
- nextLink = list.NextLink
- }
- }
- }
- }()
return out
}
diff --git a/client/rest/client.go b/client/rest/client.go
index 919edc4..a403190 100644
--- a/client/rest/client.go
+++ b/client/rest/client.go
@@ -32,16 +32,17 @@ import (
"time"
"github.com/bloodhoundad/azurehound/v2/client/config"
+ "github.com/bloodhoundad/azurehound/v2/client/query"
"github.com/bloodhoundad/azurehound/v2/constants"
)
type RestClient interface {
Authenticate() error
- Delete(ctx context.Context, path string, body interface{}, params, headers map[string]string) (*http.Response, error)
- Get(ctx context.Context, path string, params, headers map[string]string) (*http.Response, error)
- Patch(ctx context.Context, path string, body interface{}, params, headers map[string]string) (*http.Response, error)
- Post(ctx context.Context, path string, body interface{}, params, headers map[string]string) (*http.Response, error)
- Put(ctx context.Context, path string, body interface{}, params, headers map[string]string) (*http.Response, error)
+ Delete(ctx context.Context, path string, body interface{}, params query.Params, headers map[string]string) (*http.Response, error)
+ Get(ctx context.Context, path string, params query.Params, headers map[string]string) (*http.Response, error)
+ Patch(ctx context.Context, path string, body interface{}, params query.Params, headers map[string]string) (*http.Response, error)
+ Post(ctx context.Context, path string, body interface{}, params query.Params, headers map[string]string) (*http.Response, error)
+ Put(ctx context.Context, path string, body interface{}, params query.Params, headers map[string]string) (*http.Response, error)
Send(req *http.Request) (*http.Response, error)
CloseIdleConnections()
}
@@ -154,45 +155,73 @@ func (s *restClient) Authenticate() error {
}
}
-func (s *restClient) Delete(ctx context.Context, path string, body interface{}, params, headers map[string]string) (*http.Response, error) {
+func (s *restClient) Delete(ctx context.Context, path string, body interface{}, params query.Params, headers map[string]string) (*http.Response, error) {
endpoint := s.api.ResolveReference(&url.URL{Path: path})
- if req, err := NewRequest(ctx, http.MethodDelete, endpoint, body, params, headers); err != nil {
+ paramsMap := make(map[string]string)
+ if params != nil {
+ paramsMap = params.AsMap()
+ }
+ if req, err := NewRequest(ctx, http.MethodDelete, endpoint, body, paramsMap, headers); err != nil {
return nil, err
} else {
return s.Send(req)
}
}
-func (s *restClient) Get(ctx context.Context, path string, params, headers map[string]string) (*http.Response, error) {
+func (s *restClient) Get(ctx context.Context, path string, params query.Params, headers map[string]string) (*http.Response, error) {
endpoint := s.api.ResolveReference(&url.URL{Path: path})
- if req, err := NewRequest(ctx, http.MethodGet, endpoint, nil, params, headers); err != nil {
+ paramsMap := make(map[string]string)
+
+ if params != nil {
+ paramsMap = params.AsMap()
+ if params.NeedsEventualConsistencyHeaderFlag() {
+ if headers == nil {
+ headers = make(map[string]string)
+ }
+ headers["ConsistencyLevel"] = "eventual"
+ }
+ }
+
+ if req, err := NewRequest(ctx, http.MethodGet, endpoint, nil, paramsMap, headers); err != nil {
return nil, err
} else {
return s.Send(req)
}
}
-func (s *restClient) Patch(ctx context.Context, path string, body interface{}, params, headers map[string]string) (*http.Response, error) {
+func (s *restClient) Patch(ctx context.Context, path string, body interface{}, params query.Params, headers map[string]string) (*http.Response, error) {
endpoint := s.api.ResolveReference(&url.URL{Path: path})
- if req, err := NewRequest(ctx, http.MethodPatch, endpoint, body, params, headers); err != nil {
+ paramsMap := make(map[string]string)
+ if params != nil {
+ paramsMap = params.AsMap()
+ }
+ if req, err := NewRequest(ctx, http.MethodPatch, endpoint, body, paramsMap, headers); err != nil {
return nil, err
} else {
return s.Send(req)
}
}
-func (s *restClient) Post(ctx context.Context, path string, body interface{}, params, headers map[string]string) (*http.Response, error) {
+func (s *restClient) Post(ctx context.Context, path string, body interface{}, params query.Params, headers map[string]string) (*http.Response, error) {
endpoint := s.api.ResolveReference(&url.URL{Path: path})
- if req, err := NewRequest(ctx, http.MethodPost, endpoint, body, params, headers); err != nil {
+ paramsMap := make(map[string]string)
+ if params != nil {
+ paramsMap = params.AsMap()
+ }
+ if req, err := NewRequest(ctx, http.MethodPost, endpoint, body, paramsMap, headers); err != nil {
return nil, err
} else {
return s.Send(req)
}
}
-func (s *restClient) Put(ctx context.Context, path string, body interface{}, params, headers map[string]string) (*http.Response, error) {
+func (s *restClient) Put(ctx context.Context, path string, body interface{}, params query.Params, headers map[string]string) (*http.Response, error) {
endpoint := s.api.ResolveReference(&url.URL{Path: path})
- if req, err := NewRequest(ctx, http.MethodPost, endpoint, body, params, headers); err != nil {
+ paramsMap := make(map[string]string)
+ if params != nil {
+ paramsMap = params.AsMap()
+ }
+ if req, err := NewRequest(ctx, http.MethodPost, endpoint, body, paramsMap, headers); err != nil {
return nil, err
} else {
return s.Send(req)
diff --git a/client/rest/mocks/client.go b/client/rest/mocks/client.go
index b9df20b..6c2f7ae 100644
--- a/client/rest/mocks/client.go
+++ b/client/rest/mocks/client.go
@@ -9,6 +9,7 @@ import (
http "net/http"
reflect "reflect"
+ query "github.com/bloodhoundad/azurehound/v2/client/query"
gomock "go.uber.org/mock/gomock"
)
@@ -62,7 +63,7 @@ func (mr *MockRestClientMockRecorder) CloseIdleConnections() *gomock.Call {
}
// Delete mocks base method.
-func (m *MockRestClient) Delete(arg0 context.Context, arg1 string, arg2 interface{}, arg3, arg4 map[string]string) (*http.Response, error) {
+func (m *MockRestClient) Delete(arg0 context.Context, arg1 string, arg2 interface{}, arg3 query.Params, arg4 map[string]string) (*http.Response, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Delete", arg0, arg1, arg2, arg3, arg4)
ret0, _ := ret[0].(*http.Response)
@@ -77,7 +78,7 @@ func (mr *MockRestClientMockRecorder) Delete(arg0, arg1, arg2, arg3, arg4 interf
}
// Get mocks base method.
-func (m *MockRestClient) Get(arg0 context.Context, arg1 string, arg2, arg3 map[string]string) (*http.Response, error) {
+func (m *MockRestClient) Get(arg0 context.Context, arg1 string, arg2 query.Params, arg3 map[string]string) (*http.Response, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Get", arg0, arg1, arg2, arg3)
ret0, _ := ret[0].(*http.Response)
@@ -92,7 +93,7 @@ func (mr *MockRestClientMockRecorder) Get(arg0, arg1, arg2, arg3 interface{}) *g
}
// Patch mocks base method.
-func (m *MockRestClient) Patch(arg0 context.Context, arg1 string, arg2 interface{}, arg3, arg4 map[string]string) (*http.Response, error) {
+func (m *MockRestClient) Patch(arg0 context.Context, arg1 string, arg2 interface{}, arg3 query.Params, arg4 map[string]string) (*http.Response, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Patch", arg0, arg1, arg2, arg3, arg4)
ret0, _ := ret[0].(*http.Response)
@@ -107,7 +108,7 @@ func (mr *MockRestClientMockRecorder) Patch(arg0, arg1, arg2, arg3, arg4 interfa
}
// Post mocks base method.
-func (m *MockRestClient) Post(arg0 context.Context, arg1 string, arg2 interface{}, arg3, arg4 map[string]string) (*http.Response, error) {
+func (m *MockRestClient) Post(arg0 context.Context, arg1 string, arg2 interface{}, arg3 query.Params, arg4 map[string]string) (*http.Response, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Post", arg0, arg1, arg2, arg3, arg4)
ret0, _ := ret[0].(*http.Response)
@@ -122,7 +123,7 @@ func (mr *MockRestClientMockRecorder) Post(arg0, arg1, arg2, arg3, arg4 interfac
}
// Put mocks base method.
-func (m *MockRestClient) Put(arg0 context.Context, arg1 string, arg2 interface{}, arg3, arg4 map[string]string) (*http.Response, error) {
+func (m *MockRestClient) Put(arg0 context.Context, arg1 string, arg2 interface{}, arg3 query.Params, arg4 map[string]string) (*http.Response, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Put", arg0, arg1, arg2, arg3, arg4)
ret0, _ := ret[0].(*http.Response)
diff --git a/client/role_assignments.go b/client/role_assignments.go
index 34f7da1..f742f54 100644
--- a/client/role_assignments.go
+++ b/client/role_assignments.go
@@ -20,292 +20,36 @@ package client
import (
"context"
"fmt"
- "net/url"
- "strings"
"github.com/bloodhoundad/azurehound/v2/client/query"
- "github.com/bloodhoundad/azurehound/v2/client/rest"
"github.com/bloodhoundad/azurehound/v2/constants"
"github.com/bloodhoundad/azurehound/v2/models/azure"
- "github.com/bloodhoundad/azurehound/v2/panicrecovery"
- "github.com/bloodhoundad/azurehound/v2/pipeline"
)
-func (s *azureClient) GetAzureADRoleAssignment(ctx context.Context, objectId string, selectCols []string) (*azure.UnifiedRoleAssignment, error) {
+// ListAzureADRoleAssignments https://learn.microsoft.com/en-us/graph/api/rbacapplication-list-roleassignments?view=graph-rest-beta
+func (s *azureClient) ListAzureADRoleAssignments(ctx context.Context, params query.GraphParams) <-chan AzureResult[azure.UnifiedRoleAssignment] {
var (
- path = fmt.Sprintf("/%s/roleManagement/directory/roleAssignments/%s", constants.GraphApiVersion, objectId)
- params = query.Params{Select: selectCols}.AsMap()
- response azure.UnifiedRoleAssignment
- )
- if res, err := s.msgraph.Get(ctx, path, params, nil); err != nil {
- return nil, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return nil, err
- } else {
- return &response, nil
- }
-}
-
-func (s *azureClient) GetAzureADRoleAssignments(ctx context.Context, filter, search, orderBy, expand string, selectCols []string, top int32, count bool) (azure.UnifiedRoleAssignmentList, error) {
- var (
- path = fmt.Sprintf("/%s/roleManagement/directory/roleAssignments", constants.GraphApiVersion)
- params = query.Params{Filter: filter, Search: search, OrderBy: orderBy, Select: selectCols, Top: top, Count: count, Expand: expand}
- headers map[string]string
- response azure.UnifiedRoleAssignmentList
+ out = make(chan AzureResult[azure.UnifiedRoleAssignment])
+ path = fmt.Sprintf("/%s/roleManagement/directory/roleAssignments", constants.GraphApiVersion)
)
- count = count || search != "" || (filter != "" && orderBy != "") || strings.Contains(filter, "endsWith")
- if count {
- headers = make(map[string]string)
- headers["ConsistencyLevel"] = "eventual"
- }
- if res, err := s.msgraph.Get(ctx, path, params.AsMap(), headers); err != nil {
- return response, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return response, err
- } else {
- return response, nil
+ if params.Top == 0 {
+ params.Top = 999
}
-}
-
-func (s *azureClient) ListAzureADRoleAssignments(ctx context.Context, filter, search, orderBy, expand string, selectCols []string) <-chan azure.UnifiedRoleAssignmentResult {
- out := make(chan azure.UnifiedRoleAssignmentResult)
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
-
- var (
- errResult = azure.UnifiedRoleAssignmentResult{}
- nextLink string
- )
-
- if list, err := s.GetAzureADRoleAssignments(ctx, filter, search, orderBy, expand, selectCols, 999, false); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.UnifiedRoleAssignmentResult{Ok: u}); !ok {
- return
- }
- }
-
- nextLink = list.NextLink
- for nextLink != "" {
- var list azure.UnifiedRoleAssignmentList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if res, err := s.msgraph.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if err := rest.Decode(res.Body, &list); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.UnifiedRoleAssignmentResult{Ok: u}); !ok {
- return
- }
- }
- nextLink = list.NextLink
- }
- }
- }
- }()
+ go getAzureObjectList[azure.UnifiedRoleAssignment](s.msgraph, ctx, path, params, out)
return out
}
-func (s *azureClient) GetRoleAssignmentsForResource(ctx context.Context, resourceId string, filter string) (azure.RoleAssignmentList, error) {
+// ListRoleAssignmentsForResource https://learn.microsoft.com/en-us/rest/api/authorization/role-assignments/list-for-resource?view=rest-authorization-2015-07-01
+func (s *azureClient) ListRoleAssignmentsForResource(ctx context.Context, resourceId string, filter, tenantId string) <-chan AzureResult[azure.RoleAssignment] {
var (
- path = fmt.Sprintf("%s/providers/Microsoft.Authorization/roleAssignments", resourceId)
- params = query.Params{ApiVersion: "2015-07-01", Filter: filter}.AsMap()
- headers map[string]string
- response azure.RoleAssignmentList
+ out = make(chan AzureResult[azure.RoleAssignment])
+ path = fmt.Sprintf("%s/providers/Microsoft.Authorization/roleAssignments", resourceId)
+ params = query.RMParams{ApiVersion: "2015-07-01", Filter: filter, TenantId: tenantId}
)
- if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
- return response, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return response, err
- } else {
- return response, nil
- }
-
-}
-
-func (s *azureClient) ListRoleAssignmentsForResource(ctx context.Context, resourceId string, filter string) <-chan azure.RoleAssignmentResult {
- out := make(chan azure.RoleAssignmentResult)
-
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
-
- var (
- errResult = azure.RoleAssignmentResult{ParentId: resourceId}
- nextLink string
- )
-
- if result, err := s.GetRoleAssignmentsForResource(ctx, resourceId, filter); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range result.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.RoleAssignmentResult{
- ParentId: resourceId,
- Ok: u,
- }); !ok {
- return
- }
- }
-
- nextLink = result.NextLink
- for nextLink != "" {
- var list azure.RoleAssignmentList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if res, err := s.resourceManager.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if err := rest.Decode(res.Body, &list); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.RoleAssignmentResult{
- ParentId: resourceId,
- Ok: u,
- }); !ok {
- return
- }
- }
- nextLink = list.NextLink
- }
- }
- }
- }()
- return out
-}
-
-func (s *azureClient) GetResourceRoleAssignments(ctx context.Context, subscriptionId string, filter string, expand string) (azure.RoleAssignmentList, error) {
- var (
- path = fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Authorization/roleAssignments", subscriptionId)
- params = query.Params{ApiVersion: "2015-07-01", Filter: filter, Expand: expand}.AsMap()
- headers map[string]string
- response azure.RoleAssignmentList
- )
-
- if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
- return response, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return response, err
- } else {
- return response, nil
- }
-}
-
-func (s *azureClient) ListResourceRoleAssignments(ctx context.Context, subscriptionId string, filter string, expand string) <-chan azure.RoleAssignmentResult {
- out := make(chan azure.RoleAssignmentResult)
-
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
-
- var (
- errResult = azure.RoleAssignmentResult{ParentId: subscriptionId}
- nextLink string
- )
-
- if result, err := s.GetResourceRoleAssignments(ctx, subscriptionId, filter, expand); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range result.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.RoleAssignmentResult{
- ParentId: subscriptionId,
- Ok: u,
- }); !ok {
- return
- }
- }
+ go getAzureObjectList[azure.RoleAssignment](s.resourceManager, ctx, path, params, out)
- nextLink = result.NextLink
- for nextLink != "" {
- var list azure.RoleAssignmentList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if res, err := s.resourceManager.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if err := rest.Decode(res.Body, &list); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.RoleAssignmentResult{
- ParentId: subscriptionId,
- Ok: u,
- }); !ok {
- return
- }
- }
- nextLink = list.NextLink
- }
- }
- }
- }()
return out
}
diff --git a/client/roles.go b/client/roles.go
index 1f6fd5a..6299ef2 100644
--- a/client/roles.go
+++ b/client/roles.go
@@ -20,109 +20,20 @@ package client
import (
"context"
"fmt"
- "net/url"
"github.com/bloodhoundad/azurehound/v2/client/query"
- "github.com/bloodhoundad/azurehound/v2/client/rest"
"github.com/bloodhoundad/azurehound/v2/constants"
"github.com/bloodhoundad/azurehound/v2/models/azure"
- "github.com/bloodhoundad/azurehound/v2/panicrecovery"
- "github.com/bloodhoundad/azurehound/v2/pipeline"
)
-func (s *azureClient) GetAzureADRole(ctx context.Context, roleId string, selectCols []string) (*azure.Role, error) {
+// ListAzureADRoles https://learn.microsoft.com/en-us/graph/api/rbacapplication-list-roledefinitions?view=graph-rest-beta
+func (s *azureClient) ListAzureADRoles(ctx context.Context, params query.GraphParams) <-chan AzureResult[azure.Role] {
var (
- path = fmt.Sprintf("/%s/roleManagement/directory/roleDefinitions/%s", constants.GraphApiVersion, roleId)
- params = query.Params{Select: selectCols}.AsMap()
- response azure.RoleList
+ out = make(chan AzureResult[azure.Role])
+ path = fmt.Sprintf("/%s/roleManagement/directory/roleDefinitions", constants.GraphApiVersion)
)
- if res, err := s.msgraph.Get(ctx, path, params, nil); err != nil {
- return nil, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return nil, err
- } else {
- return &response.Value[0], nil
- }
-}
-
-func (s *azureClient) GetAzureADRoles(ctx context.Context, filter, expand string) (azure.RoleList, error) {
- var (
- path = fmt.Sprintf("/%s/roleManagement/directory/roleDefinitions", constants.GraphApiVersion)
- params = query.Params{Filter: filter, Expand: expand}
- headers map[string]string
- response azure.RoleList
- )
-
- if res, err := s.msgraph.Get(ctx, path, params.AsMap(), headers); err != nil {
- return response, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return response, err
- } else {
- return response, nil
- }
-}
-
-func (s *azureClient) ListAzureADRoles(ctx context.Context, filter, expand string) <-chan azure.RoleResult {
- out := make(chan azure.RoleResult)
-
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
-
- var (
- errResult = azure.RoleResult{}
- nextLink string
- )
- if users, err := s.GetAzureADRoles(ctx, filter, expand); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range users.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.RoleResult{Ok: u}); !ok {
- return
- }
- }
+ go getAzureObjectList[azure.Role](s.msgraph, ctx, path, params, out)
- nextLink = users.NextLink
- for nextLink != "" {
- var users azure.RoleList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if res, err := s.msgraph.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if err := rest.Decode(res.Body, &users); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else {
- for _, u := range users.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.RoleResult{Ok: u}); !ok {
- return
- }
- }
- nextLink = users.NextLink
- }
- }
- }
- }()
return out
}
diff --git a/client/service_principals.go b/client/service_principals.go
index 9f8642e..0c56e8c 100644
--- a/client/service_principals.go
+++ b/client/service_principals.go
@@ -19,204 +19,42 @@ package client
import (
"context"
+ "encoding/json"
"fmt"
- "net/url"
- "strings"
"github.com/bloodhoundad/azurehound/v2/client/query"
- "github.com/bloodhoundad/azurehound/v2/client/rest"
"github.com/bloodhoundad/azurehound/v2/constants"
"github.com/bloodhoundad/azurehound/v2/models/azure"
- "github.com/bloodhoundad/azurehound/v2/panicrecovery"
- "github.com/bloodhoundad/azurehound/v2/pipeline"
)
-func (s *azureClient) GetAzureADServicePrincipal(ctx context.Context, objectId string, selectCols []string) (*azure.ServicePrincipal, error) {
+// ListAzureADServicePrincipals https://learn.microsoft.com/en-us/graph/api/serviceprincipal-list?view=graph-rest-beta
+func (s *azureClient) ListAzureADServicePrincipals(ctx context.Context, params query.GraphParams) <-chan AzureResult[azure.ServicePrincipal] {
var (
- path = fmt.Sprintf("/%s/servicePrincipals/%s", constants.GraphApiVersion, objectId)
- params = query.Params{Select: selectCols}.AsMap()
- response azure.ServicePrincipalList
+ out = make(chan AzureResult[azure.ServicePrincipal])
+ path = fmt.Sprintf("/%s/servicePrincipals", constants.GraphApiVersion)
)
- if res, err := s.msgraph.Get(ctx, path, params, nil); err != nil {
- return nil, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return nil, err
- } else {
- return &response.Value[0], nil
- }
-}
-func (s *azureClient) GetAzureADServicePrincipalOwners(ctx context.Context, objectId string, filter string, search string, orderBy string, selectCols []string, top int32, count bool) (azure.DirectoryObjectList, error) {
- var (
- path = fmt.Sprintf("/%s/servicePrincipals/%s/owners", constants.GraphApiBetaVersion, objectId)
- params = query.Params{Filter: filter, Search: search, OrderBy: orderBy, Select: selectCols, Top: top, Count: count}.AsMap()
- response azure.DirectoryObjectList
- )
- if res, err := s.msgraph.Get(ctx, path, params, nil); err != nil {
- return response, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return response, err
- } else {
- return response, nil
+ if params.Top == 0 {
+ params.Top = 999
}
-}
-func (s *azureClient) GetAzureADServicePrincipals(ctx context.Context, filter, search, orderBy, expand string, selectCols []string, top int32, count bool) (azure.ServicePrincipalList, error) {
- var (
- path = fmt.Sprintf("/%s/servicePrincipals", constants.GraphApiVersion)
- params = query.Params{Filter: filter, Search: search, OrderBy: orderBy, Select: selectCols, Top: top, Count: count, Expand: expand}
- headers map[string]string
- response azure.ServicePrincipalList
- )
+ go getAzureObjectList[azure.ServicePrincipal](s.msgraph, ctx, path, params, out)
- count = count || search != "" || (filter != "" && orderBy != "") || strings.Contains(filter, "endsWith")
- if count {
- headers = make(map[string]string)
- headers["ConsistencyLevel"] = "eventual"
- }
- if res, err := s.msgraph.Get(ctx, path, params.AsMap(), headers); err != nil {
- return response, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return response, err
- } else {
- return response, nil
- }
-}
-
-func (s *azureClient) ListAzureADServicePrincipals(ctx context.Context, filter, search, orderBy, expand string, selectCols []string) <-chan azure.ServicePrincipalResult {
- out := make(chan azure.ServicePrincipalResult)
-
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
-
- var (
- errResult = azure.ServicePrincipalResult{}
- nextLink string
- )
-
- if list, err := s.GetAzureADServicePrincipals(ctx, filter, search, orderBy, expand, selectCols, 999, false); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.ServicePrincipalResult{Ok: u}); !ok {
- return
- }
- }
-
- nextLink = list.NextLink
- for nextLink != "" {
- var list azure.ServicePrincipalList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if res, err := s.msgraph.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if err := rest.Decode(res.Body, &list); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.ServicePrincipalResult{Ok: u}); !ok {
- return
- }
- }
- nextLink = list.NextLink
- }
- }
- }
- }()
return out
}
-func (s *azureClient) ListAzureADServicePrincipalOwners(ctx context.Context, objectId string, filter, search, orderBy string, selectCols []string) <-chan azure.ServicePrincipalOwnerResult {
- out := make(chan azure.ServicePrincipalOwnerResult)
-
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
+// ListAzureADServicePrincipalOwners https://learn.microsoft.com/en-us/graph/api/serviceprincipal-list-owners?view=graph-rest-beta
+func (s *azureClient) ListAzureADServicePrincipalOwners(ctx context.Context, objectId string, params query.GraphParams) <-chan AzureResult[json.RawMessage] {
+ var (
+ out = make(chan AzureResult[json.RawMessage])
+ path = fmt.Sprintf("/%s/servicePrincipals/%s/owners", constants.GraphApiBetaVersion, objectId)
+ )
- var (
- errResult = azure.ServicePrincipalOwnerResult{
- ServicePrincipalId: objectId,
- }
- nextLink string
- )
+ if params.Top == 0 {
+ params.Top = 999
+ }
- if list, err := s.GetAzureADServicePrincipalOwners(ctx, objectId, filter, search, orderBy, selectCols, 999, false); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.ServicePrincipalOwnerResult{
- ServicePrincipalId: objectId,
- Ok: u,
- }); !ok {
- return
- }
- }
+ go getAzureObjectList[json.RawMessage](s.msgraph, ctx, path, params, out)
- nextLink = list.NextLink
- for nextLink != "" {
- var list azure.DirectoryObjectList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if res, err := s.msgraph.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if err := rest.Decode(res.Body, &list); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.ServicePrincipalOwnerResult{
- ServicePrincipalId: objectId,
- Ok: u,
- }); !ok {
- return
- }
- }
- nextLink = list.NextLink
- }
- }
- }
- }()
return out
}
diff --git a/client/storage_accounts.go b/client/storage_accounts.go
index 920deb1..402d247 100644
--- a/client/storage_accounts.go
+++ b/client/storage_accounts.go
@@ -20,114 +20,21 @@ package client
import (
"context"
"fmt"
- "net/url"
"github.com/bloodhoundad/azurehound/v2/client/query"
- "github.com/bloodhoundad/azurehound/v2/client/rest"
"github.com/bloodhoundad/azurehound/v2/models/azure"
- "github.com/bloodhoundad/azurehound/v2/panicrecovery"
- "github.com/bloodhoundad/azurehound/v2/pipeline"
)
-func (s *azureClient) GetAzureStorageAccount(ctx context.Context, subscriptionId, groupName, saName, expand string) (*azure.StorageAccount, error) {
+// ListAzureStorageAccounts https://learn.microsoft.com/en-us/rest/api/storagerp/storage-accounts/list?view=rest-storagerp-2022-05-01
+func (s *azureClient) ListAzureStorageAccounts(ctx context.Context, subscriptionId string) <-chan AzureResult[azure.StorageAccount] {
var (
- path = fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Storage/storageAccounts/%s", subscriptionId, groupName, saName)
- params = query.Params{ApiVersion: "2021-07-01", Expand: expand}.AsMap()
- headers map[string]string
- response azure.StorageAccount
+ out = make(chan AzureResult[azure.StorageAccount])
+ path = fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Storage/storageAccounts", subscriptionId)
+ params = query.RMParams{ApiVersion: "2022-05-01"}
)
- if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
- return nil, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return nil, err
- } else {
- return &response, nil
- }
-}
-
-func (s *azureClient) GetAzureStorageAccounts(ctx context.Context, subscriptionId string) (azure.StorageAccountList, error) {
- var (
- path = fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Storage/storageAccounts", subscriptionId)
- params = query.Params{ApiVersion: "2022-05-01"}.AsMap()
- headers map[string]string
- response azure.StorageAccountList
- )
- if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
- return response, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return response, err
- } else {
- return response, nil
- }
-}
-
-func (s *azureClient) ListAzureStorageAccounts(ctx context.Context, subscriptionId string) <-chan azure.StorageAccountResult {
- out := make(chan azure.StorageAccountResult)
-
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
-
- var (
- errResult = azure.StorageAccountResult{
- SubscriptionId: subscriptionId,
- }
- nextLink string
- )
- if result, err := s.GetAzureStorageAccounts(ctx, subscriptionId); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range result.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.StorageAccountResult{SubscriptionId: subscriptionId, Ok: u}); !ok {
- return
- }
- }
+ go getAzureObjectList[azure.StorageAccount](s.resourceManager, ctx, path, params, out)
- nextLink = result.NextLink
- for nextLink != "" {
- var list azure.StorageAccountList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if res, err := s.resourceManager.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if err := rest.Decode(res.Body, &list); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.StorageAccountResult{
- SubscriptionId: "/subscriptions/" + subscriptionId,
- Ok: u,
- }); !ok {
- return
- }
- }
- nextLink = list.NextLink
- }
- }
- }
- }()
return out
}
@@ -135,104 +42,15 @@ func (s *azureClient) ListAzureStorageAccounts(ctx context.Context, subscription
// Storage containers
// ==
-func (s *azureClient) GetAzureStorageContainer(ctx context.Context, subscriptionId string, resourceGroupName string, saName string, scName string, filter string, includeDeleted string, maxPageSize string) (*azure.StorageContainer, error) {
+// ListAzureStorageContainers https://learn.microsoft.com/en-us/rest/api/storagerp/blob-containers/list?view=rest-storagerp-2022-05-01
+func (s *azureClient) ListAzureStorageContainers(ctx context.Context, subscriptionId string, resourceGroupName string, saName string, filter string, includeDeleted string, maxPageSize string) <-chan AzureResult[azure.StorageContainer] {
var (
- path = fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Storage/storageAccounts/%s/blobServices/default/containers/%s", subscriptionId, resourceGroupName, saName, scName)
- params = query.Params{ApiVersion: "2022-05-01", Filter: filter, IncludeDeleted: includeDeleted, MaxPageSize: maxPageSize}.AsMap()
- headers map[string]string
- response azure.StorageContainer
+ out = make(chan AzureResult[azure.StorageContainer])
+ path = fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Storage/storageAccounts/%s/blobServices/default/containers", subscriptionId, resourceGroupName, saName)
+ params = query.RMParams{ApiVersion: "2022-05-01", Filter: filter, IncludeDeleted: includeDeleted, MaxPageSize: maxPageSize}
)
- if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
- return nil, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return nil, err
- } else {
- return &response, nil
- }
-}
-
-func (s *azureClient) GetAzureStorageContainers(ctx context.Context, subscriptionId string, resourceGroupName string, saName string, filter string, includeDeleted string, maxPageSize string) (azure.StorageContainerList, error) {
- var (
- path = fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Storage/storageAccounts/%s/blobServices/default/containers", subscriptionId, resourceGroupName, saName)
- params = query.Params{ApiVersion: "2022-05-01", Filter: filter, IncludeDeleted: includeDeleted, MaxPageSize: maxPageSize}.AsMap()
- headers map[string]string
- response azure.StorageContainerList
- )
- if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
- return response, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return response, err
- } else {
- return response, nil
- }
-}
-
-func (s *azureClient) ListAzureStorageContainers(ctx context.Context, subscriptionId string, resourceGroupName string, saName string, filter string, includeDeleted string, maxPageSize string) <-chan azure.StorageContainerResult {
- out := make(chan azure.StorageContainerResult)
-
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
-
- var (
- errResult = azure.StorageContainerResult{
- SubscriptionId: subscriptionId,
- }
- nextLink string
- )
- if result, err := s.GetAzureStorageContainers(ctx, subscriptionId, resourceGroupName, saName, filter, includeDeleted, maxPageSize); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range result.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.StorageContainerResult{SubscriptionId: subscriptionId, Ok: u}); !ok {
- return
- }
- }
+ go getAzureObjectList[azure.StorageContainer](s.resourceManager, ctx, path, params, out)
- nextLink = result.NextLink
- for nextLink != "" {
- var list azure.StorageContainerList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if res, err := s.resourceManager.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if err := rest.Decode(res.Body, &list); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.StorageContainerResult{
- SubscriptionId: "/subscriptions/" + subscriptionId,
- Ok: u,
- }); !ok {
- return
- }
- }
- nextLink = list.NextLink
- }
- }
- }
- }()
return out
}
diff --git a/client/subscriptions.go b/client/subscriptions.go
index 877d18b..0ed8933 100644
--- a/client/subscriptions.go
+++ b/client/subscriptions.go
@@ -19,110 +19,20 @@ package client
import (
"context"
- "fmt"
- "net/url"
"github.com/bloodhoundad/azurehound/v2/client/query"
- "github.com/bloodhoundad/azurehound/v2/client/rest"
"github.com/bloodhoundad/azurehound/v2/models/azure"
- "github.com/bloodhoundad/azurehound/v2/panicrecovery"
- "github.com/bloodhoundad/azurehound/v2/pipeline"
)
-func (s *azureClient) GetAzureSubscription(ctx context.Context, objectId string) (*azure.Subscription, error) {
+// ListAzureSubscriptions https://learn.microsoft.com/en-us/rest/api/subscription/subscriptions/list?view=rest-subscription-2020-01-01
+func (s *azureClient) ListAzureSubscriptions(ctx context.Context) <-chan AzureResult[azure.Subscription] {
var (
- path = fmt.Sprintf("/subscriptions/%s", objectId)
- params = query.Params{ApiVersion: "2020-01-01"}.AsMap()
- headers map[string]string
- response azure.Subscription
+ out = make(chan AzureResult[azure.Subscription])
+ path = "/subscriptions"
+ params = query.RMParams{ApiVersion: "2020-01-01"}
)
- if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
- return nil, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return nil, err
- } else {
- return &response, nil
- }
-}
-
-func (s *azureClient) GetAzureSubscriptions(ctx context.Context) (azure.SubscriptionList, error) {
- var (
- path = "/subscriptions"
- params = query.Params{ApiVersion: "2020-01-01"}.AsMap()
- headers map[string]string
- response azure.SubscriptionList
- )
-
- if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
- return response, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return response, err
- } else {
- return response, nil
- }
-}
-
-func (s *azureClient) ListAzureSubscriptions(ctx context.Context) <-chan azure.SubscriptionResult {
- out := make(chan azure.SubscriptionResult)
-
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
-
- var (
- errResult = azure.SubscriptionResult{}
- nextLink string
- )
- if result, err := s.GetAzureSubscriptions(ctx); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range result.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.SubscriptionResult{Ok: u}); !ok {
- return
- }
- }
+ go getAzureObjectList[azure.Subscription](s.resourceManager, ctx, path, params, out)
- nextLink = result.NextLink
- for nextLink != "" {
- var list azure.SubscriptionList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if res, err := s.resourceManager.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if err := rest.Decode(res.Body, &list); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.SubscriptionResult{Ok: u}); !ok {
- return
- }
- }
- nextLink = list.NextLink
- }
- }
- }
- }()
return out
}
diff --git a/client/tenants.go b/client/tenants.go
index 1584190..4aa8966 100644
--- a/client/tenants.go
+++ b/client/tenants.go
@@ -20,23 +20,19 @@ package client
import (
"context"
"fmt"
- "net/url"
"github.com/bloodhoundad/azurehound/v2/client/query"
"github.com/bloodhoundad/azurehound/v2/client/rest"
"github.com/bloodhoundad/azurehound/v2/constants"
"github.com/bloodhoundad/azurehound/v2/models/azure"
- "github.com/bloodhoundad/azurehound/v2/panicrecovery"
- "github.com/bloodhoundad/azurehound/v2/pipeline"
)
func (s *azureClient) GetAzureADOrganization(ctx context.Context, selectCols []string) (*azure.Organization, error) {
var (
path = fmt.Sprintf("/%s/organization", constants.GraphApiVersion)
- params = query.Params{Select: selectCols}.AsMap()
response azure.OrganizationList
)
- if res, err := s.msgraph.Get(ctx, path, params, nil); err != nil {
+ if res, err := s.msgraph.Get(ctx, path, query.GraphParams{Select: selectCols}, nil); err != nil {
return nil, err
} else if err := rest.Decode(res.Body, &response); err != nil {
return nil, err
@@ -48,7 +44,7 @@ func (s *azureClient) GetAzureADOrganization(ctx context.Context, selectCols []s
func (s *azureClient) GetAzureADTenants(ctx context.Context, includeAllTenantCategories bool) (azure.TenantList, error) {
var (
path = "/tenants"
- params = query.Params{ApiVersion: "2020-01-01", IncludeAllTenantCategories: includeAllTenantCategories}.AsMap()
+ params = query.RMParams{ApiVersion: "2020-01-01", IncludeAllTenantCategories: includeAllTenantCategories}
headers map[string]string
response azure.TenantList
)
@@ -62,67 +58,15 @@ func (s *azureClient) GetAzureADTenants(ctx context.Context, includeAllTenantCat
}
}
-func (s *azureClient) ListAzureADTenants(ctx context.Context, includeAllTenantCategories bool) <-chan azure.TenantResult {
- out := make(chan azure.TenantResult)
-
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
-
- var (
- errResult = azure.TenantResult{}
- nextLink string
- )
+// ListAzureADTenants https://learn.microsoft.com/en-us/rest/api/subscription/tenants/list?view=rest-subscription-2020-01-01
+func (s *azureClient) ListAzureADTenants(ctx context.Context, includeAllTenantCategories bool) <-chan AzureResult[azure.Tenant] {
+ var (
+ out = make(chan AzureResult[azure.Tenant])
+ path = "/tenants"
+ params = query.RMParams{ApiVersion: "2020-01-01", IncludeAllTenantCategories: includeAllTenantCategories}
+ )
- if result, err := s.GetAzureADTenants(ctx, includeAllTenantCategories); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range result.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.TenantResult{Ok: u}); !ok {
- return
- }
- }
+ go getAzureObjectList[azure.Tenant](s.resourceManager, ctx, path, params, out)
- nextLink = result.NextLink
- for nextLink != "" {
- var list azure.TenantList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if res, err := s.resourceManager.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if err := rest.Decode(res.Body, &list); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.TenantResult{Ok: u}); !ok {
- return
- }
- }
- nextLink = list.NextLink
- }
- }
- }
- }()
return out
}
diff --git a/client/users.go b/client/users.go
index cea543d..d20f4bf 100644
--- a/client/users.go
+++ b/client/users.go
@@ -20,114 +20,24 @@ package client
import (
"context"
"fmt"
- "net/url"
- "strings"
"github.com/bloodhoundad/azurehound/v2/client/query"
- "github.com/bloodhoundad/azurehound/v2/client/rest"
"github.com/bloodhoundad/azurehound/v2/constants"
"github.com/bloodhoundad/azurehound/v2/models/azure"
- "github.com/bloodhoundad/azurehound/v2/panicrecovery"
- "github.com/bloodhoundad/azurehound/v2/pipeline"
)
-func (s *azureClient) GetAzureADUser(ctx context.Context, objectId string, selectCols []string) (*azure.User, error) {
+// ListAzureADUsers https://learn.microsoft.com/en-us/graph/api/user-list?view=graph-rest-beta
+func (s *azureClient) ListAzureADUsers(ctx context.Context, params query.GraphParams) <-chan AzureResult[azure.User] {
var (
- path = fmt.Sprintf("/%s/users/%s", constants.GraphApiVersion, objectId)
- params = query.Params{Select: selectCols}.AsMap()
- response azure.UserList
- )
- if res, err := s.msgraph.Get(ctx, path, params, nil); err != nil {
- return nil, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return nil, err
- } else {
- return &response.Value[0], nil
- }
-}
-
-func (s *azureClient) GetAzureADUsers(ctx context.Context, filter string, search string, orderBy string, selectCols []string, top int32, count bool) (azure.UserList, error) {
- var (
- path = fmt.Sprintf("/%s/users", constants.GraphApiVersion)
- params = query.Params{Filter: filter, Search: search, OrderBy: orderBy, Select: selectCols, Top: top, Count: count}
- headers map[string]string
- response azure.UserList
+ out = make(chan AzureResult[azure.User])
+ path = fmt.Sprintf("/%s/users", constants.GraphApiVersion)
)
- count = count || search != "" || (filter != "" && orderBy != "") || strings.Contains(filter, "endsWith")
- if count {
- headers = make(map[string]string)
- headers["ConsistencyLevel"] = "eventual"
+ if params.Top == 0 {
+ params.Top = 999
}
- if res, err := s.msgraph.Get(ctx, path, params.AsMap(), headers); err != nil {
- return response, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return response, err
- } else {
- return response, nil
- }
-}
-
-func (s *azureClient) ListAzureADUsers(ctx context.Context, filter string, search string, orderBy string, selectCols []string) <-chan azure.UserResult {
- out := make(chan azure.UserResult)
-
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
- var (
- errResult = azure.UserResult{}
- nextLink string
- )
- if users, err := s.GetAzureADUsers(ctx, filter, search, orderBy, selectCols, 999, false); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range users.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.UserResult{Ok: u}); !ok {
- return
- }
- }
+ go getAzureObjectList[azure.User](s.msgraph, ctx, path, params, out)
- nextLink = users.NextLink
- for nextLink != "" {
- var users azure.UserList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if res, err := s.msgraph.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if err := rest.Decode(res.Body, &users); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else {
- for _, u := range users.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.UserResult{Ok: u}); !ok {
- return
- }
- }
- nextLink = users.NextLink
- }
- }
- }
- }()
return out
}
diff --git a/client/virtual_machines.go b/client/virtual_machines.go
index 1934974..673d36c 100644
--- a/client/virtual_machines.go
+++ b/client/virtual_machines.go
@@ -20,114 +20,23 @@ package client
import (
"context"
"fmt"
- "net/url"
"github.com/bloodhoundad/azurehound/v2/client/query"
- "github.com/bloodhoundad/azurehound/v2/client/rest"
"github.com/bloodhoundad/azurehound/v2/models/azure"
- "github.com/bloodhoundad/azurehound/v2/panicrecovery"
- "github.com/bloodhoundad/azurehound/v2/pipeline"
)
-func (s *azureClient) GetAzureVirtualMachine(ctx context.Context, subscriptionId, groupName, vmName, expand string) (*azure.VirtualMachine, error) {
+// ListAzureVirtualMachines https://learn.microsoft.com/en-us/rest/api/compute/virtual-machines/list-all?view=rest-compute-2021-07-01
+func (s *azureClient) ListAzureVirtualMachines(ctx context.Context, subscriptionId string, params query.RMParams) <-chan AzureResult[azure.VirtualMachine] {
var (
- path = fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/virtualMachines/%s", subscriptionId, groupName, vmName)
- params = query.Params{ApiVersion: "2021-07-01", Expand: expand}.AsMap()
- headers map[string]string
- response azure.VirtualMachine
- )
- if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
- return nil, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return nil, err
- } else {
- return &response, nil
- }
-}
-
-func (s *azureClient) GetAzureVirtualMachines(ctx context.Context, subscriptionId string, statusOnly bool) (azure.VirtualMachineList, error) {
- var (
- path = fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Compute/virtualMachines", subscriptionId)
- params = query.Params{ApiVersion: "2021-07-01", StatusOnly: statusOnly}.AsMap()
- headers map[string]string
- response azure.VirtualMachineList
+ out = make(chan AzureResult[azure.VirtualMachine])
+ path = fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Compute/virtualMachines", subscriptionId)
)
- if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
- return response, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return response, err
- } else {
- return response, nil
+ if params.ApiVersion == "" {
+ params.ApiVersion = "2021-07-01"
}
-}
-
-func (s *azureClient) ListAzureVirtualMachines(ctx context.Context, subscriptionId string, statusOnly bool) <-chan azure.VirtualMachineResult {
- out := make(chan azure.VirtualMachineResult)
-
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
-
- var (
- errResult = azure.VirtualMachineResult{
- SubscriptionId: subscriptionId,
- }
- nextLink string
- )
- if result, err := s.GetAzureVirtualMachines(ctx, subscriptionId, statusOnly); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range result.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.VirtualMachineResult{SubscriptionId: subscriptionId, Ok: u}); !ok {
- return
- }
- }
+ go getAzureObjectList[azure.VirtualMachine](s.resourceManager, ctx, path, params, out)
- nextLink = result.NextLink
- for nextLink != "" {
- var list azure.VirtualMachineList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if res, err := s.resourceManager.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if err := rest.Decode(res.Body, &list); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.VirtualMachineResult{
- SubscriptionId: "/subscriptions/" + subscriptionId,
- Ok: u,
- }); !ok {
- return
- }
- }
- nextLink = list.NextLink
- }
- }
- }
- }()
return out
}
diff --git a/client/vm_scale_sets.go b/client/vm_scale_sets.go
index 94879ad..8ac1e42 100644
--- a/client/vm_scale_sets.go
+++ b/client/vm_scale_sets.go
@@ -20,114 +20,20 @@ package client
import (
"context"
"fmt"
- "net/url"
"github.com/bloodhoundad/azurehound/v2/client/query"
- "github.com/bloodhoundad/azurehound/v2/client/rest"
"github.com/bloodhoundad/azurehound/v2/models/azure"
- "github.com/bloodhoundad/azurehound/v2/panicrecovery"
- "github.com/bloodhoundad/azurehound/v2/pipeline"
)
-func (s *azureClient) GetAzureVMScaleSet(ctx context.Context, subscriptionId, groupName, vmssName, expand string) (*azure.VMScaleSet, error) {
+// ListAzureVMScaleSets https://learn.microsoft.com/en-us/rest/api/compute/virtual-machine-scale-sets/list-all?view=rest-compute-2022-11-01
+func (s *azureClient) ListAzureVMScaleSets(ctx context.Context, subscriptionId string) <-chan AzureResult[azure.VMScaleSet] {
var (
- path = fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/virtualMachineScaleSets/%s", subscriptionId, groupName, vmssName)
- params = query.Params{ApiVersion: "2022-11-01", Expand: expand}.AsMap()
- headers map[string]string
- response azure.VMScaleSet
+ out = make(chan AzureResult[azure.VMScaleSet])
+ path = fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Compute/virtualMachineScaleSets", subscriptionId)
+ params = query.RMParams{ApiVersion: "2022-11-01"}
)
- if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
- return nil, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return nil, err
- } else {
- return &response, nil
- }
-}
-
-func (s *azureClient) GetAzureVMScaleSets(ctx context.Context, subscriptionId string, statusOnly bool) (azure.VMScaleSetList, error) {
- var (
- path = fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Compute/virtualMachineScaleSets", subscriptionId)
- params = query.Params{ApiVersion: "2022-11-01", StatusOnly: statusOnly}.AsMap()
- headers map[string]string
- response azure.VMScaleSetList
- )
-
- if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
- return response, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return response, err
- } else {
- return response, nil
- }
-}
-
-func (s *azureClient) ListAzureVMScaleSets(ctx context.Context, subscriptionId string, statusOnly bool) <-chan azure.VMScaleSetResult {
- out := make(chan azure.VMScaleSetResult)
-
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
-
- var (
- errResult = azure.VMScaleSetResult{
- SubscriptionId: subscriptionId,
- }
- nextLink string
- )
- if result, err := s.GetAzureVMScaleSets(ctx, subscriptionId, statusOnly); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range result.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.VMScaleSetResult{SubscriptionId: subscriptionId, Ok: u}); !ok {
- return
- }
- }
+ go getAzureObjectList[azure.VMScaleSet](s.resourceManager, ctx, path, params, out)
- nextLink = result.NextLink
- for nextLink != "" {
- var list azure.VMScaleSetList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if res, err := s.resourceManager.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if err := rest.Decode(res.Body, &list); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.VMScaleSetResult{
- SubscriptionId: "/subscriptions/" + subscriptionId,
- Ok: u,
- }); !ok {
- return
- }
- }
- nextLink = list.NextLink
- }
- }
- }
- }()
return out
}
diff --git a/client/web_apps.go b/client/web_apps.go
index d25fdfc..4ae12fc 100644
--- a/client/web_apps.go
+++ b/client/web_apps.go
@@ -20,114 +20,20 @@ package client
import (
"context"
"fmt"
- "net/url"
"github.com/bloodhoundad/azurehound/v2/client/query"
- "github.com/bloodhoundad/azurehound/v2/client/rest"
"github.com/bloodhoundad/azurehound/v2/models/azure"
- "github.com/bloodhoundad/azurehound/v2/panicrecovery"
- "github.com/bloodhoundad/azurehound/v2/pipeline"
)
-func (s *azureClient) GetAzureWebApp(ctx context.Context, subscriptionId, groupName, waName, expand string) (*azure.WebApp, error) {
+// ListAzureWebApps https://learn.microsoft.com/en-us/rest/api/appservice/web-apps/list?view=rest-appservice-2022-03-01
+func (s *azureClient) ListAzureWebApps(ctx context.Context, subscriptionId string) <-chan AzureResult[azure.WebApp] {
+ out := make(chan AzureResult[azure.WebApp])
var (
- path = fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Web/sites/%s", subscriptionId, groupName, waName)
- params = query.Params{ApiVersion: "2022-03-01", Expand: expand}.AsMap()
- headers map[string]string
- response azure.WebApp
+ path = fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Web/sites", subscriptionId)
+ params = query.RMParams{ApiVersion: "2022-03-01"}
)
- if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
- return nil, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return nil, err
- } else {
- return &response, nil
- }
-}
-
-func (s *azureClient) GetAzureWebApps(ctx context.Context, subscriptionId string) (azure.WebAppList, error) {
- var (
- path = fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Web/sites", subscriptionId)
- params = query.Params{ApiVersion: "2022-03-01"}.AsMap()
- headers map[string]string
- response azure.WebAppList
- )
-
- if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
- return response, err
- } else if err := rest.Decode(res.Body, &response); err != nil {
- return response, err
- } else {
- return response, nil
- }
-}
-
-func (s *azureClient) ListAzureWebApps(ctx context.Context, subscriptionId string) <-chan azure.WebAppResult {
- out := make(chan azure.WebAppResult)
-
- go func() {
- defer panicrecovery.PanicRecovery()
- defer close(out)
-
- var (
- errResult = azure.WebAppResult{
- SubscriptionId: subscriptionId,
- }
- nextLink string
- )
- if result, err := s.GetAzureWebApps(ctx, subscriptionId); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- } else {
- for _, u := range result.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.WebAppResult{SubscriptionId: subscriptionId, Ok: u}); !ok {
- return
- }
- }
+ go getAzureObjectList[azure.WebApp](s.resourceManager, ctx, path, params, out)
- nextLink = result.NextLink
- for nextLink != "" {
- var list azure.WebAppList
- if url, err := url.Parse(nextLink); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if res, err := s.resourceManager.Send(req); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else if err := rest.Decode(res.Body, &list); err != nil {
- errResult.Error = err
- if ok := pipeline.Send(ctx.Done(), out, errResult); !ok {
- return
- }
- nextLink = ""
- } else {
- for _, u := range list.Value {
- if ok := pipeline.Send(ctx.Done(), out, azure.WebAppResult{
- SubscriptionId: "/subscriptions/" + subscriptionId,
- Ok: u,
- }); !ok {
- return
- }
- }
- nextLink = list.NextLink
- }
- }
- }
- }()
return out
}
diff --git a/cmd/list-app-owners.go b/cmd/list-app-owners.go
index 5fe7336..56df1b5 100644
--- a/cmd/list-app-owners.go
+++ b/cmd/list-app-owners.go
@@ -25,6 +25,7 @@ import (
"time"
"github.com/bloodhoundad/azurehound/v2/client"
+ "github.com/bloodhoundad/azurehound/v2/client/query"
"github.com/bloodhoundad/azurehound/v2/enums"
"github.com/bloodhoundad/azurehound/v2/models"
"github.com/bloodhoundad/azurehound/v2/panicrecovery"
@@ -63,6 +64,7 @@ func listAppOwners(ctx context.Context, client client.AzureClient, apps <-chan a
out = make(chan azureWrapper[models.AppOwners])
streams = pipeline.Demux(ctx.Done(), apps, 25)
wg sync.WaitGroup
+ params = query.GraphParams{}
)
wg.Add(len(streams))
@@ -78,13 +80,13 @@ func listAppOwners(ctx context.Context, client client.AzureClient, apps <-chan a
}
count = 0
)
- for item := range client.ListAzureADAppOwners(ctx, app.Data.Id, "", "", "", nil) {
+ for item := range client.ListAzureADAppOwners(ctx, app.Data.Id, params) {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing owners for this app", "appId", app.Data.AppId)
} else {
appOwner := models.AppOwner{
Owner: item.Ok,
- AppId: item.AppId,
+ AppId: app.Data.Id,
}
log.V(2).Info("found app owner", "appOwner", appOwner)
count++
diff --git a/cmd/list-app-owners_test.go b/cmd/list-app-owners_test.go
index 666d8f1..978b7a8 100644
--- a/cmd/list-app-owners_test.go
+++ b/cmd/list-app-owners_test.go
@@ -23,6 +23,7 @@ import (
"fmt"
"testing"
+ "github.com/bloodhoundad/azurehound/v2/client"
"github.com/bloodhoundad/azurehound/v2/client/mocks"
"github.com/bloodhoundad/azurehound/v2/enums"
"github.com/bloodhoundad/azurehound/v2/models"
@@ -42,14 +43,14 @@ func TestListAppOwners(t *testing.T) {
mockClient := mocks.NewMockAzureClient(ctrl)
mockAppsChannel := make(chan azureWrapper[models.App])
- mockAppOwnerChannel := make(chan azure.AppOwnerResult)
- mockAppOwnerChannel2 := make(chan azure.AppOwnerResult)
+ mockAppOwnerChannel := make(chan client.AzureResult[json.RawMessage])
+ mockAppOwnerChannel2 := make(chan client.AzureResult[json.RawMessage])
mockTenant := azure.Tenant{}
mockError := fmt.Errorf("I'm an error")
mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes()
- mockClient.EXPECT().ListAzureADAppOwners(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockAppOwnerChannel).Times(1)
- mockClient.EXPECT().ListAzureADAppOwners(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockAppOwnerChannel2).Times(1)
+ mockClient.EXPECT().ListAzureADAppOwners(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockAppOwnerChannel).Times(1)
+ mockClient.EXPECT().ListAzureADAppOwners(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockAppOwnerChannel2).Times(1)
channel := listAppOwners(ctx, mockClient, mockAppsChannel)
go func() {
@@ -59,19 +60,19 @@ func TestListAppOwners(t *testing.T) {
}()
go func() {
defer close(mockAppOwnerChannel)
- mockAppOwnerChannel <- azure.AppOwnerResult{
+ mockAppOwnerChannel <- client.AzureResult[json.RawMessage]{
Ok: json.RawMessage{},
}
- mockAppOwnerChannel <- azure.AppOwnerResult{
+ mockAppOwnerChannel <- client.AzureResult[json.RawMessage]{
Ok: json.RawMessage{},
}
}()
go func() {
defer close(mockAppOwnerChannel2)
- mockAppOwnerChannel2 <- azure.AppOwnerResult{
+ mockAppOwnerChannel2 <- client.AzureResult[json.RawMessage]{
Ok: json.RawMessage{},
}
- mockAppOwnerChannel2 <- azure.AppOwnerResult{
+ mockAppOwnerChannel2 <- client.AzureResult[json.RawMessage]{
Error: mockError,
}
}()
diff --git a/cmd/list-app-role-assignments.go b/cmd/list-app-role-assignments.go
index 9e3aa4b..cbff4a7 100644
--- a/cmd/list-app-role-assignments.go
+++ b/cmd/list-app-role-assignments.go
@@ -26,6 +26,7 @@ import (
"time"
"github.com/bloodhoundad/azurehound/v2/client"
+ "github.com/bloodhoundad/azurehound/v2/client/query"
"github.com/bloodhoundad/azurehound/v2/enums"
"github.com/bloodhoundad/azurehound/v2/models"
"github.com/bloodhoundad/azurehound/v2/panicrecovery"
@@ -96,7 +97,7 @@ func listAppRoleAssignments(ctx context.Context, client client.AzureClient, serv
var (
count = 0
)
- for item := range client.ListAzureADAppRoleAssignments(ctx, servicePrincipal.Id, "", "", "", "", nil) {
+ for item := range client.ListAzureADAppRoleAssignments(ctx, servicePrincipal.Id, query.GraphParams{}) {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing app role assignments for this service principal", "servicePrincipalId", servicePrincipal)
} else {
diff --git a/cmd/list-apps.go b/cmd/list-apps.go
index 8160eb6..aabec3e 100644
--- a/cmd/list-apps.go
+++ b/cmd/list-apps.go
@@ -24,6 +24,7 @@ import (
"time"
"github.com/bloodhoundad/azurehound/v2/client"
+ "github.com/bloodhoundad/azurehound/v2/client/query"
"github.com/bloodhoundad/azurehound/v2/enums"
"github.com/bloodhoundad/azurehound/v2/models"
"github.com/bloodhoundad/azurehound/v2/panicrecovery"
@@ -64,7 +65,7 @@ func listApps(ctx context.Context, client client.AzureClient) <-chan azureWrappe
defer panicrecovery.PanicRecovery()
defer close(out)
count := 0
- for item := range client.ListAzureADApps(ctx, "", "", "", "", nil) {
+ for item := range client.ListAzureADApps(ctx, query.GraphParams{}) {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing applications")
return
diff --git a/cmd/list-apps_test.go b/cmd/list-apps_test.go
index 136656a..136d8f0 100644
--- a/cmd/list-apps_test.go
+++ b/cmd/list-apps_test.go
@@ -22,6 +22,7 @@ import (
"fmt"
"testing"
+ "github.com/bloodhoundad/azurehound/v2/client"
"github.com/bloodhoundad/azurehound/v2/client/mocks"
"github.com/bloodhoundad/azurehound/v2/models/azure"
"go.uber.org/mock/gomock"
@@ -37,21 +38,21 @@ func TestListApps(t *testing.T) {
ctx := context.Background()
mockClient := mocks.NewMockAzureClient(ctrl)
- mockChannel := make(chan azure.ApplicationResult)
+ mockChannel := make(chan client.AzureResult[azure.Application])
mockTenant := azure.Tenant{}
mockError := fmt.Errorf("I'm an error")
mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes()
- mockClient.EXPECT().ListAzureADApps(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockChannel)
+ mockClient.EXPECT().ListAzureADApps(gomock.Any(), gomock.Any()).Return(mockChannel)
go func() {
defer close(mockChannel)
- mockChannel <- azure.ApplicationResult{
+ mockChannel <- client.AzureResult[azure.Application]{
Ok: azure.Application{},
}
- mockChannel <- azure.ApplicationResult{
+ mockChannel <- client.AzureResult[azure.Application]{
Error: mockError,
}
- mockChannel <- azure.ApplicationResult{
+ mockChannel <- client.AzureResult[azure.Application]{
Ok: azure.Application{},
}
}()
diff --git a/cmd/list-automation-account-role-assignments.go b/cmd/list-automation-account-role-assignments.go
index 7b25179..3a15f9d 100644
--- a/cmd/list-automation-account-role-assignments.go
+++ b/cmd/list-automation-account-role-assignments.go
@@ -98,7 +98,7 @@ func listAutomationAccountRoleAssignments(ctx context.Context, client client.Azu
}
count = 0
)
- for item := range client.ListRoleAssignmentsForResource(ctx, id, "") {
+ for item := range client.ListRoleAssignmentsForResource(ctx, id, "", "") {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing role assignments for this automation account", "automationAccountId", id)
} else {
@@ -106,7 +106,7 @@ func listAutomationAccountRoleAssignments(ctx context.Context, client client.Azu
automationAccountRoleAssignment := models.AzureRoleAssignment{
Assignee: item.Ok,
- ObjectId: item.ParentId,
+ ObjectId: id,
RoleDefinitionId: roleDefinitionId,
}
log.V(2).Info("found automation account role assignment", "automationAccountRoleAssignment", automationAccountRoleAssignment)
diff --git a/cmd/list-automation-accounts.go b/cmd/list-automation-accounts.go
index bd51f48..1887964 100644
--- a/cmd/list-automation-accounts.go
+++ b/cmd/list-automation-accounts.go
@@ -97,7 +97,7 @@ func listAutomationAccounts(ctx context.Context, client client.AzureClient, subs
resourceGroupId := item.Ok.ResourceGroupId()
automationAccount := models.AutomationAccount{
AutomationAccount: item.Ok,
- SubscriptionId: item.SubscriptionId,
+ SubscriptionId: "/subscriptions/" + id,
ResourceGroupId: resourceGroupId,
TenantId: client.TenantInfo().TenantId,
}
diff --git a/cmd/list-container-registries.go b/cmd/list-container-registries.go
index 93a0932..dcdc379 100644
--- a/cmd/list-container-registries.go
+++ b/cmd/list-container-registries.go
@@ -102,7 +102,7 @@ func listContainerRegistries(ctx context.Context, client client.AzureClient, sub
resourceGroupId := item.Ok.ResourceGroupId()
containerRegistry := models.ContainerRegistry{
ContainerRegistry: item.Ok,
- SubscriptionId: item.SubscriptionId,
+ SubscriptionId: "/subscriptions/" + id,
ResourceGroupId: resourceGroupId,
TenantId: client.TenantInfo().TenantId,
}
diff --git a/cmd/list-container-registry-role-assignments.go b/cmd/list-container-registry-role-assignments.go
index 31c3806..8c3a44a 100644
--- a/cmd/list-container-registry-role-assignments.go
+++ b/cmd/list-container-registry-role-assignments.go
@@ -103,7 +103,7 @@ func listContainerRegistryRoleAssignments(ctx context.Context, client client.Azu
}
count = 0
)
- for item := range client.ListRoleAssignmentsForResource(ctx, id, "") {
+ for item := range client.ListRoleAssignmentsForResource(ctx, id, "", "") {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing role assignments for this container registry", "containerRegistryId", id)
} else {
@@ -111,7 +111,7 @@ func listContainerRegistryRoleAssignments(ctx context.Context, client client.Azu
containerRegistryRoleAssignment := models.AzureRoleAssignment{
Assignee: item.Ok,
- ObjectId: item.ParentId,
+ ObjectId: id,
RoleDefinitionId: roleDefinitionId,
}
log.V(2).Info("found container registry role assignment", "containerRegistryRoleAssignment", containerRegistryRoleAssignment)
diff --git a/cmd/list-device-owners.go b/cmd/list-device-owners.go
index 1d0c2e6..4fcc48d 100644
--- a/cmd/list-device-owners.go
+++ b/cmd/list-device-owners.go
@@ -26,6 +26,7 @@ import (
"time"
"github.com/bloodhoundad/azurehound/v2/client"
+ "github.com/bloodhoundad/azurehound/v2/client/query"
"github.com/bloodhoundad/azurehound/v2/enums"
"github.com/bloodhoundad/azurehound/v2/models"
"github.com/bloodhoundad/azurehound/v2/panicrecovery"
@@ -95,13 +96,13 @@ func listDeviceOwners(ctx context.Context, client client.AzureClient, devices <-
}
count = 0
)
- for item := range client.ListAzureDeviceRegisteredOwners(ctx, id, false) {
+ for item := range client.ListAzureDeviceRegisteredOwners(ctx, id, query.GraphParams{}) {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing owners for this device", "deviceId", id)
} else {
deviceOwner := models.DeviceOwner{
Owner: item.Ok,
- DeviceId: item.DeviceId,
+ DeviceId: id,
}
log.V(2).Info("found device owner", "deviceOwner", deviceOwner)
count++
diff --git a/cmd/list-device-owners_test.go b/cmd/list-device-owners_test.go
index 5f0dc3e..87a2306 100644
--- a/cmd/list-device-owners_test.go
+++ b/cmd/list-device-owners_test.go
@@ -23,6 +23,7 @@ import (
"fmt"
"testing"
+ "github.com/bloodhoundad/azurehound/v2/client"
"github.com/bloodhoundad/azurehound/v2/client/mocks"
"github.com/bloodhoundad/azurehound/v2/models"
"github.com/bloodhoundad/azurehound/v2/models/azure"
@@ -41,8 +42,8 @@ func TestListDeviceOwners(t *testing.T) {
mockClient := mocks.NewMockAzureClient(ctrl)
mockDevicesChannel := make(chan interface{})
- mockDeviceOwnerChannel := make(chan azure.DeviceRegisteredOwnerResult)
- mockDeviceOwnerChannel2 := make(chan azure.DeviceRegisteredOwnerResult)
+ mockDeviceOwnerChannel := make(chan client.AzureResult[json.RawMessage])
+ mockDeviceOwnerChannel2 := make(chan client.AzureResult[json.RawMessage])
mockTenant := azure.Tenant{}
mockError := fmt.Errorf("I'm an error")
@@ -62,19 +63,19 @@ func TestListDeviceOwners(t *testing.T) {
}()
go func() {
defer close(mockDeviceOwnerChannel)
- mockDeviceOwnerChannel <- azure.DeviceRegisteredOwnerResult{
+ mockDeviceOwnerChannel <- client.AzureResult[json.RawMessage]{
Ok: json.RawMessage{},
}
- mockDeviceOwnerChannel <- azure.DeviceRegisteredOwnerResult{
+ mockDeviceOwnerChannel <- client.AzureResult[json.RawMessage]{
Ok: json.RawMessage{},
}
}()
go func() {
defer close(mockDeviceOwnerChannel2)
- mockDeviceOwnerChannel2 <- azure.DeviceRegisteredOwnerResult{
+ mockDeviceOwnerChannel2 <- client.AzureResult[json.RawMessage]{
Ok: json.RawMessage{},
}
- mockDeviceOwnerChannel2 <- azure.DeviceRegisteredOwnerResult{
+ mockDeviceOwnerChannel2 <- client.AzureResult[json.RawMessage]{
Error: mockError,
}
}()
diff --git a/cmd/list-devices.go b/cmd/list-devices.go
index 5e68b8b..184b5bb 100644
--- a/cmd/list-devices.go
+++ b/cmd/list-devices.go
@@ -24,6 +24,7 @@ import (
"time"
"github.com/bloodhoundad/azurehound/v2/client"
+ "github.com/bloodhoundad/azurehound/v2/client/query"
"github.com/bloodhoundad/azurehound/v2/enums"
"github.com/bloodhoundad/azurehound/v2/models"
"github.com/bloodhoundad/azurehound/v2/panicrecovery"
@@ -64,7 +65,7 @@ func listDevices(ctx context.Context, client client.AzureClient) <-chan interfac
defer panicrecovery.PanicRecovery()
defer close(out)
count := 0
- for item := range client.ListAzureDevices(ctx, "", "", "", "", nil) {
+ for item := range client.ListAzureDevices(ctx, query.GraphParams{}) {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing devices")
return
diff --git a/cmd/list-devices_test.go b/cmd/list-devices_test.go
index 1bbf4bf..a2a19ed 100644
--- a/cmd/list-devices_test.go
+++ b/cmd/list-devices_test.go
@@ -22,6 +22,7 @@ import (
"fmt"
"testing"
+ "github.com/bloodhoundad/azurehound/v2/client"
"github.com/bloodhoundad/azurehound/v2/client/mocks"
"github.com/bloodhoundad/azurehound/v2/models/azure"
"go.uber.org/mock/gomock"
@@ -37,21 +38,21 @@ func TestListDevices(t *testing.T) {
ctx := context.Background()
mockClient := mocks.NewMockAzureClient(ctrl)
- mockChannel := make(chan azure.DeviceResult)
+ mockChannel := make(chan client.AzureResult[azure.Device])
mockTenant := azure.Tenant{}
mockError := fmt.Errorf("I'm an error")
mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes()
- mockClient.EXPECT().ListAzureDevices(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockChannel)
+ mockClient.EXPECT().ListAzureDevices(gomock.Any(), gomock.Any()).Return(mockChannel)
go func() {
defer close(mockChannel)
- mockChannel <- azure.DeviceResult{
+ mockChannel <- client.AzureResult[azure.Device]{
Ok: azure.Device{},
}
- mockChannel <- azure.DeviceResult{
+ mockChannel <- client.AzureResult[azure.Device]{
Error: mockError,
}
- mockChannel <- azure.DeviceResult{
+ mockChannel <- client.AzureResult[azure.Device]{
Ok: azure.Device{},
}
}()
diff --git a/cmd/list-function-app-role-assignments.go b/cmd/list-function-app-role-assignments.go
index d881936..56d5d9b 100644
--- a/cmd/list-function-app-role-assignments.go
+++ b/cmd/list-function-app-role-assignments.go
@@ -98,7 +98,7 @@ func listFunctionAppRoleAssignments(ctx context.Context, client client.AzureClie
}
count = 0
)
- for item := range client.ListRoleAssignmentsForResource(ctx, id, "") {
+ for item := range client.ListRoleAssignmentsForResource(ctx, id, "", "") {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing role assignments for this function app", "functionAppId", id)
} else {
@@ -106,7 +106,7 @@ func listFunctionAppRoleAssignments(ctx context.Context, client client.AzureClie
functionAppRoleAssignment := models.AzureRoleAssignment{
Assignee: item.Ok,
- ObjectId: item.ParentId,
+ ObjectId: id,
RoleDefinitionId: roleDefinitionId,
}
log.V(2).Info("Found function app role asignment", "functionAppRoleAssignment", functionAppRoleAssignment)
diff --git a/cmd/list-function-apps.go b/cmd/list-function-apps.go
index d4e9b56..7f961ab 100644
--- a/cmd/list-function-apps.go
+++ b/cmd/list-function-apps.go
@@ -94,12 +94,12 @@ func listFunctionApps(ctx context.Context, client client.AzureClient, subscripti
if item.Error != nil {
log.Error(item.Error, "unable to continue processing function apps for this subscription", "subscriptionId", id)
} else {
- resourceGroupId := item.Ok.ResourceGroupId()
functionApp := models.FunctionApp{
- FunctionApp: item.Ok,
- SubscriptionId: item.SubscriptionId,
- ResourceGroupId: resourceGroupId,
- TenantId: client.TenantInfo().TenantId,
+ FunctionApp: item.Ok,
+ SubscriptionId: "/subscriptions/" + id,
+ ResourceGroupId: item.Ok.ResourceGroupId(),
+ ResourceGroupName: item.Ok.ResourceGroupName(),
+ TenantId: client.TenantInfo().TenantId,
}
if functionApp.Kind == "functionapp" {
log.V(2).Info("found function app", "functionApp", functionApp)
diff --git a/cmd/list-group-members.go b/cmd/list-group-members.go
index 2f534a0..c465d6b 100644
--- a/cmd/list-group-members.go
+++ b/cmd/list-group-members.go
@@ -26,6 +26,7 @@ import (
"time"
"github.com/bloodhoundad/azurehound/v2/client"
+ "github.com/bloodhoundad/azurehound/v2/client/query"
"github.com/bloodhoundad/azurehound/v2/enums"
"github.com/bloodhoundad/azurehound/v2/models"
"github.com/bloodhoundad/azurehound/v2/panicrecovery"
@@ -35,6 +36,7 @@ import (
func init() {
listRootCmd.AddCommand(listGroupMembersCmd)
+ listGroupMembersCmd.Flags().StringSliceVar(&listGroupMembersSelect, "select", []string{"id,displayName,createdDateTime"}, `Select properties to include. Use "" for Azure default properties. Azurehound default is "id,displayName,createdDateTime" if flag is not supplied.`)
}
var listGroupMembersCmd = &cobra.Command{
@@ -44,7 +46,9 @@ var listGroupMembersCmd = &cobra.Command{
SilenceUsage: true,
}
-func listGroupMembersCmdImpl(cmd *cobra.Command, args []string) {
+var listGroupMembersSelect []string
+
+func listGroupMembersCmdImpl(cmd *cobra.Command, _ []string) {
ctx, stop := signal.NotifyContext(cmd.Context(), os.Interrupt, os.Kill)
defer gracefulShutdown(stop)
@@ -64,6 +68,14 @@ func listGroupMembers(ctx context.Context, client client.AzureClient, groups <-c
ids = make(chan string)
streams = pipeline.Demux(ctx.Done(), ids, 25)
wg sync.WaitGroup
+ params = query.GraphParams{
+ Select: unique(listGroupMembersSelect),
+ Filter: "",
+ Count: false,
+ Search: "",
+ Top: 0,
+ Expand: "",
+ }
)
go func() {
@@ -95,13 +107,13 @@ func listGroupMembers(ctx context.Context, client client.AzureClient, groups <-c
}
count = 0
)
- for item := range client.ListAzureADGroupMembers(ctx, id, "", "", "", nil) {
+ for item := range client.ListAzureADGroupMembers(ctx, id, params) {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing members for this group", "groupId", id)
} else {
groupMember := models.GroupMember{
Member: item.Ok,
- GroupId: item.ParentId,
+ GroupId: id,
}
log.V(2).Info("found group member", "groupMember", groupMember)
count++
diff --git a/cmd/list-group-members_test.go b/cmd/list-group-members_test.go
index f3cf088..495d28f 100644
--- a/cmd/list-group-members_test.go
+++ b/cmd/list-group-members_test.go
@@ -23,6 +23,7 @@ import (
"fmt"
"testing"
+ "github.com/bloodhoundad/azurehound/v2/client"
"github.com/bloodhoundad/azurehound/v2/client/mocks"
"github.com/bloodhoundad/azurehound/v2/models"
"github.com/bloodhoundad/azurehound/v2/models/azure"
@@ -41,14 +42,14 @@ func TestListGroupMembers(t *testing.T) {
mockClient := mocks.NewMockAzureClient(ctrl)
mockGroupsChannel := make(chan interface{})
- mockGroupMemberChannel := make(chan azure.MemberObjectResult)
- mockGroupMemberChannel2 := make(chan azure.MemberObjectResult)
+ mockGroupMemberChannel := make(chan client.AzureResult[json.RawMessage])
+ mockGroupMemberChannel2 := make(chan client.AzureResult[json.RawMessage])
mockTenant := azure.Tenant{}
mockError := fmt.Errorf("I'm an error")
mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes()
- mockClient.EXPECT().ListAzureADGroupMembers(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockGroupMemberChannel).Times(1)
- mockClient.EXPECT().ListAzureADGroupMembers(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockGroupMemberChannel2).Times(1)
+ mockClient.EXPECT().ListAzureADGroupMembers(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockGroupMemberChannel).Times(1)
+ mockClient.EXPECT().ListAzureADGroupMembers(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockGroupMemberChannel2).Times(1)
channel := listGroupMembers(ctx, mockClient, mockGroupsChannel)
go func() {
@@ -62,19 +63,19 @@ func TestListGroupMembers(t *testing.T) {
}()
go func() {
defer close(mockGroupMemberChannel)
- mockGroupMemberChannel <- azure.MemberObjectResult{
+ mockGroupMemberChannel <- client.AzureResult[json.RawMessage]{
Ok: json.RawMessage{},
}
- mockGroupMemberChannel <- azure.MemberObjectResult{
+ mockGroupMemberChannel <- client.AzureResult[json.RawMessage]{
Ok: json.RawMessage{},
}
}()
go func() {
defer close(mockGroupMemberChannel2)
- mockGroupMemberChannel2 <- azure.MemberObjectResult{
+ mockGroupMemberChannel2 <- client.AzureResult[json.RawMessage]{
Ok: json.RawMessage{},
}
- mockGroupMemberChannel2 <- azure.MemberObjectResult{
+ mockGroupMemberChannel2 <- client.AzureResult[json.RawMessage]{
Error: mockError,
}
}()
diff --git a/cmd/list-group-owners.go b/cmd/list-group-owners.go
index e24d13b..ed077d7 100644
--- a/cmd/list-group-owners.go
+++ b/cmd/list-group-owners.go
@@ -26,6 +26,7 @@ import (
"time"
"github.com/bloodhoundad/azurehound/v2/client"
+ "github.com/bloodhoundad/azurehound/v2/client/query"
"github.com/bloodhoundad/azurehound/v2/enums"
"github.com/bloodhoundad/azurehound/v2/models"
"github.com/bloodhoundad/azurehound/v2/panicrecovery"
@@ -64,6 +65,7 @@ func listGroupOwners(ctx context.Context, client client.AzureClient, groups <-ch
ids = make(chan string)
streams = pipeline.Demux(ctx.Done(), ids, 25)
wg sync.WaitGroup
+ params = query.GraphParams{}
)
go func() {
@@ -95,13 +97,13 @@ func listGroupOwners(ctx context.Context, client client.AzureClient, groups <-ch
}
count = 0
)
- for item := range client.ListAzureADGroupOwners(ctx, id, "", "", "", nil) {
+ for item := range client.ListAzureADGroupOwners(ctx, id, params) {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing owners for this group", "groupId", id)
} else {
groupOwner := models.GroupOwner{
Owner: item.Ok,
- GroupId: item.GroupId,
+ GroupId: id,
}
log.V(2).Info("found group owner", "groupOwner", groupOwner)
count++
diff --git a/cmd/list-group-owners_test.go b/cmd/list-group-owners_test.go
index b1e7eea..57e8536 100644
--- a/cmd/list-group-owners_test.go
+++ b/cmd/list-group-owners_test.go
@@ -23,6 +23,7 @@ import (
"fmt"
"testing"
+ "github.com/bloodhoundad/azurehound/v2/client"
"github.com/bloodhoundad/azurehound/v2/client/mocks"
"github.com/bloodhoundad/azurehound/v2/models"
"github.com/bloodhoundad/azurehound/v2/models/azure"
@@ -41,14 +42,14 @@ func TestListGroupOwners(t *testing.T) {
mockClient := mocks.NewMockAzureClient(ctrl)
mockGroupsChannel := make(chan interface{})
- mockGroupOwnerChannel := make(chan azure.GroupOwnerResult)
- mockGroupOwnerChannel2 := make(chan azure.GroupOwnerResult)
+ mockGroupOwnerChannel := make(chan client.AzureResult[json.RawMessage])
+ mockGroupOwnerChannel2 := make(chan client.AzureResult[json.RawMessage])
mockTenant := azure.Tenant{}
mockError := fmt.Errorf("I'm an error")
mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes()
- mockClient.EXPECT().ListAzureADGroupOwners(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockGroupOwnerChannel).Times(1)
- mockClient.EXPECT().ListAzureADGroupOwners(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockGroupOwnerChannel2).Times(1)
+ mockClient.EXPECT().ListAzureADGroupOwners(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockGroupOwnerChannel).Times(1)
+ mockClient.EXPECT().ListAzureADGroupOwners(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockGroupOwnerChannel2).Times(1)
channel := listGroupOwners(ctx, mockClient, mockGroupsChannel)
go func() {
@@ -62,19 +63,19 @@ func TestListGroupOwners(t *testing.T) {
}()
go func() {
defer close(mockGroupOwnerChannel)
- mockGroupOwnerChannel <- azure.GroupOwnerResult{
+ mockGroupOwnerChannel <- client.AzureResult[json.RawMessage]{
Ok: json.RawMessage{},
}
- mockGroupOwnerChannel <- azure.GroupOwnerResult{
+ mockGroupOwnerChannel <- client.AzureResult[json.RawMessage]{
Ok: json.RawMessage{},
}
}()
go func() {
defer close(mockGroupOwnerChannel2)
- mockGroupOwnerChannel2 <- azure.GroupOwnerResult{
+ mockGroupOwnerChannel2 <- client.AzureResult[json.RawMessage]{
Ok: json.RawMessage{},
}
- mockGroupOwnerChannel2 <- azure.GroupOwnerResult{
+ mockGroupOwnerChannel2 <- client.AzureResult[json.RawMessage]{
Error: mockError,
}
}()
diff --git a/cmd/list-groups.go b/cmd/list-groups.go
index 47b8dde..0031d39 100644
--- a/cmd/list-groups.go
+++ b/cmd/list-groups.go
@@ -24,6 +24,7 @@ import (
"time"
"github.com/bloodhoundad/azurehound/v2/client"
+ "github.com/bloodhoundad/azurehound/v2/client/query"
"github.com/bloodhoundad/azurehound/v2/enums"
"github.com/bloodhoundad/azurehound/v2/models"
"github.com/bloodhoundad/azurehound/v2/panicrecovery"
@@ -42,7 +43,7 @@ var listGroupsCmd = &cobra.Command{
SilenceUsage: true,
}
-func listGroupsCmdImpl(cmd *cobra.Command, args []string) {
+func listGroupsCmdImpl(cmd *cobra.Command, _ []string) {
ctx, stop := signal.NotifyContext(cmd.Context(), os.Interrupt, os.Kill)
defer gracefulShutdown(stop)
@@ -64,7 +65,7 @@ func listGroups(ctx context.Context, client client.AzureClient) <-chan interface
defer panicrecovery.PanicRecovery()
defer close(out)
count := 0
- for item := range client.ListAzureADGroups(ctx, "securityEnabled eq true", "", "", "", nil) {
+ for item := range client.ListAzureADGroups(ctx, query.GraphParams{Filter: "securityEnabled eq true"}) {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing groups")
return
diff --git a/cmd/list-groups_test.go b/cmd/list-groups_test.go
index d931ff2..175a74e 100644
--- a/cmd/list-groups_test.go
+++ b/cmd/list-groups_test.go
@@ -22,6 +22,7 @@ import (
"fmt"
"testing"
+ "github.com/bloodhoundad/azurehound/v2/client"
"github.com/bloodhoundad/azurehound/v2/client/mocks"
"github.com/bloodhoundad/azurehound/v2/models/azure"
"go.uber.org/mock/gomock"
@@ -38,21 +39,21 @@ func TestListGroups(t *testing.T) {
ctx := context.Background()
mockClient := mocks.NewMockAzureClient(ctrl)
- mockChannel := make(chan azure.GroupResult)
+ mockChannel := make(chan client.AzureResult[azure.Group])
mockTenant := azure.Tenant{}
mockError := fmt.Errorf("I'm an error")
mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes()
- mockClient.EXPECT().ListAzureADGroups(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockChannel)
+ mockClient.EXPECT().ListAzureADGroups(gomock.Any(), gomock.Any()).Return(mockChannel)
go func() {
defer close(mockChannel)
- mockChannel <- azure.GroupResult{
+ mockChannel <- client.AzureResult[azure.Group]{
Ok: azure.Group{},
}
- mockChannel <- azure.GroupResult{
+ mockChannel <- client.AzureResult[azure.Group]{
Error: mockError,
}
- mockChannel <- azure.GroupResult{
+ mockChannel <- client.AzureResult[azure.Group]{
Ok: azure.Group{},
}
}()
diff --git a/cmd/list-key-vault-role-assignments.go b/cmd/list-key-vault-role-assignments.go
index 05b67d2..0780c8b 100644
--- a/cmd/list-key-vault-role-assignments.go
+++ b/cmd/list-key-vault-role-assignments.go
@@ -97,12 +97,12 @@ func listKeyVaultRoleAssignments(ctx context.Context, client client.AzureClient,
}
count = 0
)
- for item := range client.ListRoleAssignmentsForResource(ctx, id, "") {
+ for item := range client.ListRoleAssignmentsForResource(ctx, id, "", "") {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing role assignments for this key vault", "keyVaultId", id)
} else {
keyVaultRoleAssignment := models.KeyVaultRoleAssignment{
- KeyVaultId: item.ParentId,
+ KeyVaultId: id,
RoleAssignment: item.Ok,
}
log.V(2).Info("found key vault role assignment", "keyVaultRoleAssignment", keyVaultRoleAssignment)
diff --git a/cmd/list-key-vault-role-assignments_test.go b/cmd/list-key-vault-role-assignments_test.go
index db7e4c3..d94018e 100644
--- a/cmd/list-key-vault-role-assignments_test.go
+++ b/cmd/list-key-vault-role-assignments_test.go
@@ -22,6 +22,7 @@ import (
"fmt"
"testing"
+ "github.com/bloodhoundad/azurehound/v2/client"
"github.com/bloodhoundad/azurehound/v2/client/mocks"
"github.com/bloodhoundad/azurehound/v2/constants"
"github.com/bloodhoundad/azurehound/v2/models"
@@ -41,14 +42,14 @@ func TestListKeyVaultRoleAssignments(t *testing.T) {
mockClient := mocks.NewMockAzureClient(ctrl)
mockKeyVaultsChannel := make(chan interface{})
- mockKeyVaultRoleAssignmentChannel := make(chan azure.RoleAssignmentResult)
- mockKeyVaultRoleAssignmentChannel2 := make(chan azure.RoleAssignmentResult)
+ mockKeyVaultRoleAssignmentChannel := make(chan client.AzureResult[azure.RoleAssignment])
+ mockKeyVaultRoleAssignmentChannel2 := make(chan client.AzureResult[azure.RoleAssignment])
mockTenant := azure.Tenant{}
mockError := fmt.Errorf("I'm an error")
mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes()
- mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockKeyVaultRoleAssignmentChannel).Times(1)
- mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockKeyVaultRoleAssignmentChannel2).Times(1)
+ mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockKeyVaultRoleAssignmentChannel).Times(1)
+ mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockKeyVaultRoleAssignmentChannel2).Times(1)
channel := listKeyVaultRoleAssignments(ctx, mockClient, mockKeyVaultsChannel)
go func() {
@@ -62,14 +63,14 @@ func TestListKeyVaultRoleAssignments(t *testing.T) {
}()
go func() {
defer close(mockKeyVaultRoleAssignmentChannel)
- mockKeyVaultRoleAssignmentChannel <- azure.RoleAssignmentResult{
+ mockKeyVaultRoleAssignmentChannel <- client.AzureResult[azure.RoleAssignment]{
Ok: azure.RoleAssignment{
Properties: azure.RoleAssignmentPropertiesWithScope{
RoleDefinitionId: constants.KeyVaultContributorRoleID,
},
},
}
- mockKeyVaultRoleAssignmentChannel <- azure.RoleAssignmentResult{
+ mockKeyVaultRoleAssignmentChannel <- client.AzureResult[azure.RoleAssignment]{
Ok: azure.RoleAssignment{
Properties: azure.RoleAssignmentPropertiesWithScope{
RoleDefinitionId: constants.ContributorRoleID,
@@ -79,14 +80,14 @@ func TestListKeyVaultRoleAssignments(t *testing.T) {
}()
go func() {
defer close(mockKeyVaultRoleAssignmentChannel2)
- mockKeyVaultRoleAssignmentChannel2 <- azure.RoleAssignmentResult{
+ mockKeyVaultRoleAssignmentChannel2 <- client.AzureResult[azure.RoleAssignment]{
Ok: azure.RoleAssignment{
Properties: azure.RoleAssignmentPropertiesWithScope{
RoleDefinitionId: constants.KeyVaultAdministratorRoleID,
},
},
}
- mockKeyVaultRoleAssignmentChannel2 <- azure.RoleAssignmentResult{
+ mockKeyVaultRoleAssignmentChannel2 <- client.AzureResult[azure.RoleAssignment]{
Error: mockError,
}
}()
diff --git a/cmd/list-key-vaults.go b/cmd/list-key-vaults.go
index 66626d4..6ea7641 100644
--- a/cmd/list-key-vaults.go
+++ b/cmd/list-key-vaults.go
@@ -26,6 +26,7 @@ import (
"time"
"github.com/bloodhoundad/azurehound/v2/client"
+ "github.com/bloodhoundad/azurehound/v2/client/query"
"github.com/bloodhoundad/azurehound/v2/enums"
"github.com/bloodhoundad/azurehound/v2/models"
"github.com/bloodhoundad/azurehound/v2/panicrecovery"
@@ -91,17 +92,16 @@ func listKeyVaults(ctx context.Context, client client.AzureClient, subscriptions
defer wg.Done()
for id := range stream {
count := 0
- for item := range client.ListAzureKeyVaults(ctx, id, 999) {
+ for item := range client.ListAzureKeyVaults(ctx, id, query.RMParams{Top: 999}) {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing key vaults for this subscription", "subscriptionId", id)
} else {
- resourceGroup := item.Ok.ResourceGroupId()
// the embedded struct's values override top-level properties so TenantId
// needs to be explicitly set.
keyVault := models.KeyVault{
KeyVault: item.Ok,
- SubscriptionId: item.SubscriptionId,
- ResourceGroup: resourceGroup,
+ SubscriptionId: id,
+ ResourceGroup: item.Ok.ResourceGroupId(),
TenantId: item.Ok.Properties.TenantId,
}
log.V(2).Info("found key vault", "keyVault", keyVault)
diff --git a/cmd/list-key-vaults_test.go b/cmd/list-key-vaults_test.go
index 269288a..9629d02 100644
--- a/cmd/list-key-vaults_test.go
+++ b/cmd/list-key-vaults_test.go
@@ -22,6 +22,7 @@ import (
"fmt"
"testing"
+ "github.com/bloodhoundad/azurehound/v2/client"
"github.com/bloodhoundad/azurehound/v2/client/mocks"
"github.com/bloodhoundad/azurehound/v2/models"
"github.com/bloodhoundad/azurehound/v2/models/azure"
@@ -40,8 +41,8 @@ func TestListKeyVaults(t *testing.T) {
mockClient := mocks.NewMockAzureClient(ctrl)
mockSubscriptionsChannel := make(chan interface{})
- mockKeyVaultChannel := make(chan azure.KeyVaultResult)
- mockKeyVaultChannel2 := make(chan azure.KeyVaultResult)
+ mockKeyVaultChannel := make(chan client.AzureResult[azure.KeyVault])
+ mockKeyVaultChannel2 := make(chan client.AzureResult[azure.KeyVault])
mockTenant := azure.Tenant{}
mockError := fmt.Errorf("I'm an error")
@@ -61,19 +62,19 @@ func TestListKeyVaults(t *testing.T) {
}()
go func() {
defer close(mockKeyVaultChannel)
- mockKeyVaultChannel <- azure.KeyVaultResult{
+ mockKeyVaultChannel <- client.AzureResult[azure.KeyVault]{
Ok: azure.KeyVault{},
}
- mockKeyVaultChannel <- azure.KeyVaultResult{
+ mockKeyVaultChannel <- client.AzureResult[azure.KeyVault]{
Ok: azure.KeyVault{},
}
}()
go func() {
defer close(mockKeyVaultChannel2)
- mockKeyVaultChannel2 <- azure.KeyVaultResult{
+ mockKeyVaultChannel2 <- client.AzureResult[azure.KeyVault]{
Ok: azure.KeyVault{},
}
- mockKeyVaultChannel2 <- azure.KeyVaultResult{
+ mockKeyVaultChannel2 <- client.AzureResult[azure.KeyVault]{
Error: mockError,
}
}()
diff --git a/cmd/list-logic-app-role-assignments.go b/cmd/list-logic-app-role-assignments.go
index 0dd33aa..8768970 100644
--- a/cmd/list-logic-app-role-assignments.go
+++ b/cmd/list-logic-app-role-assignments.go
@@ -103,7 +103,7 @@ func listLogicAppRoleAssignments(ctx context.Context, client client.AzureClient,
}
count = 0
)
- for item := range client.ListRoleAssignmentsForResource(ctx, id, "") {
+ for item := range client.ListRoleAssignmentsForResource(ctx, id, "", "") {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing role assignments for this logic app", "logicappId", id)
} else {
@@ -111,7 +111,7 @@ func listLogicAppRoleAssignments(ctx context.Context, client client.AzureClient,
logicappRoleAssignment := models.AzureRoleAssignment{
Assignee: item.Ok,
- ObjectId: item.ParentId,
+ ObjectId: id,
RoleDefinitionId: roleDefinitionId,
}
log.V(2).Info("found logic app role assignment", "logicappRoleAssignment", logicappRoleAssignment)
diff --git a/cmd/list-logic-apps.go b/cmd/list-logic-apps.go
index 415168d..e60c26c 100644
--- a/cmd/list-logic-apps.go
+++ b/cmd/list-logic-apps.go
@@ -104,11 +104,10 @@ func listLogicApps(ctx context.Context, client client.AzureClient, subscriptions
if item.Error != nil {
log.Error(item.Error, "unable to continue processing logic apps for this subscription", "subscriptionId", id)
} else {
- resourceGroupId := item.Ok.ResourceGroupId()
logicapp := models.LogicApp{
LogicApp: item.Ok,
- SubscriptionId: item.SubscriptionId,
- ResourceGroupId: resourceGroupId,
+ SubscriptionId: "/subscriptions/" + id,
+ ResourceGroupId: item.Ok.ResourceGroupId(),
TenantId: client.TenantInfo().TenantId,
}
log.V(2).Info("found logicapp", "logicapp", logicapp)
diff --git a/cmd/list-managed-cluster-role-assignments.go b/cmd/list-managed-cluster-role-assignments.go
index 102db09..82e09a3 100644
--- a/cmd/list-managed-cluster-role-assignments.go
+++ b/cmd/list-managed-cluster-role-assignments.go
@@ -103,7 +103,7 @@ func listManagedClusterRoleAssignments(ctx context.Context, client client.AzureC
}
count = 0
)
- for item := range client.ListRoleAssignmentsForResource(ctx, id, "") {
+ for item := range client.ListRoleAssignmentsForResource(ctx, id, "", "") {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing role assignments for this managed cluster", "managedClusterId", id)
} else {
@@ -111,7 +111,7 @@ func listManagedClusterRoleAssignments(ctx context.Context, client client.AzureC
managedClusterRoleAssignment := models.AzureRoleAssignment{
Assignee: item.Ok,
- ObjectId: item.ParentId,
+ ObjectId: id,
RoleDefinitionId: roleDefinitionId,
}
log.V(2).Info("found managed cluster role assignment", "managedClusterRoleAssignment", managedClusterRoleAssignment)
diff --git a/cmd/list-managed-clusters.go b/cmd/list-managed-clusters.go
index d186666..61fe220 100644
--- a/cmd/list-managed-clusters.go
+++ b/cmd/list-managed-clusters.go
@@ -95,15 +95,14 @@ func listManagedClusters(ctx context.Context, client client.AzureClient, subscri
defer wg.Done()
for id := range stream {
count := 0
- for item := range client.ListAzureManagedClusters(ctx, id, false) {
+ for item := range client.ListAzureManagedClusters(ctx, id) {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing managed clusters for this subscription", "subscriptionId", id)
} else {
- resourceGroupId := item.Ok.ResourceGroupId()
managedCluster := models.ManagedCluster{
ManagedCluster: item.Ok,
- SubscriptionId: item.SubscriptionId,
- ResourceGroupId: resourceGroupId,
+ SubscriptionId: "/subscriptions/" + id,
+ ResourceGroupId: item.Ok.ResourceGroupId(),
TenantId: client.TenantInfo().TenantId,
}
log.V(2).Info("found managed cluster", "managedCluster", managedCluster)
diff --git a/cmd/list-management-group-descendants.go b/cmd/list-management-group-descendants.go
index 404c56e..803b20f 100644
--- a/cmd/list-management-group-descendants.go
+++ b/cmd/list-management-group-descendants.go
@@ -91,7 +91,7 @@ func listManagementGroupDescendants(ctx context.Context, client client.AzureClie
defer wg.Done()
for id := range stream {
count := 0
- for item := range client.ListAzureManagementGroupDescendants(ctx, id) {
+ for item := range client.ListAzureManagementGroupDescendants(ctx, id, 3000) {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing descendants for this management group", "managementGroupId", id)
} else {
diff --git a/cmd/list-management-group-descendants_test.go b/cmd/list-management-group-descendants_test.go
index 01806b1..3b3e53a 100644
--- a/cmd/list-management-group-descendants_test.go
+++ b/cmd/list-management-group-descendants_test.go
@@ -22,6 +22,7 @@ import (
"fmt"
"testing"
+ "github.com/bloodhoundad/azurehound/v2/client"
"github.com/bloodhoundad/azurehound/v2/client/mocks"
"github.com/bloodhoundad/azurehound/v2/models"
"github.com/bloodhoundad/azurehound/v2/models/azure"
@@ -40,14 +41,14 @@ func TestListManagementGroupDescendants(t *testing.T) {
mockClient := mocks.NewMockAzureClient(ctrl)
mockManagementGroupsChannel := make(chan interface{})
- mockManagementGroupDescendantChannel := make(chan azure.DescendantInfoResult)
- mockManagementGroupDescendantChannel2 := make(chan azure.DescendantInfoResult)
+ mockManagementGroupDescendantChannel := make(chan client.AzureResult[azure.DescendantInfo])
+ mockManagementGroupDescendantChannel2 := make(chan client.AzureResult[azure.DescendantInfo])
mockTenant := azure.Tenant{}
mockError := fmt.Errorf("I'm an error")
mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes()
- mockClient.EXPECT().ListAzureManagementGroupDescendants(gomock.Any(), gomock.Any()).Return(mockManagementGroupDescendantChannel).Times(1)
- mockClient.EXPECT().ListAzureManagementGroupDescendants(gomock.Any(), gomock.Any()).Return(mockManagementGroupDescendantChannel2).Times(1)
+ mockClient.EXPECT().ListAzureManagementGroupDescendants(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockManagementGroupDescendantChannel).Times(1)
+ mockClient.EXPECT().ListAzureManagementGroupDescendants(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockManagementGroupDescendantChannel2).Times(1)
channel := listManagementGroupDescendants(ctx, mockClient, mockManagementGroupsChannel)
go func() {
@@ -61,13 +62,13 @@ func TestListManagementGroupDescendants(t *testing.T) {
}()
go func() {
defer close(mockManagementGroupDescendantChannel)
- mockManagementGroupDescendantChannel <- azure.DescendantInfoResult{}
- mockManagementGroupDescendantChannel <- azure.DescendantInfoResult{}
+ mockManagementGroupDescendantChannel <- client.AzureResult[azure.DescendantInfo]{}
+ mockManagementGroupDescendantChannel <- client.AzureResult[azure.DescendantInfo]{}
}()
go func() {
defer close(mockManagementGroupDescendantChannel2)
- mockManagementGroupDescendantChannel2 <- azure.DescendantInfoResult{}
- mockManagementGroupDescendantChannel2 <- azure.DescendantInfoResult{
+ mockManagementGroupDescendantChannel2 <- client.AzureResult[azure.DescendantInfo]{}
+ mockManagementGroupDescendantChannel2 <- client.AzureResult[azure.DescendantInfo]{
Error: mockError,
}
}()
diff --git a/cmd/list-management-group-role-assignments.go b/cmd/list-management-group-role-assignments.go
index 6ef9a51..97009b4 100644
--- a/cmd/list-management-group-role-assignments.go
+++ b/cmd/list-management-group-role-assignments.go
@@ -97,12 +97,12 @@ func listManagementGroupRoleAssignments(ctx context.Context, client client.Azure
}
count = 0
)
- for item := range client.ListRoleAssignmentsForResource(ctx, id, "atScope()") {
+ for item := range client.ListRoleAssignmentsForResource(ctx, id, "atScope()", "") {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing role assignments for this managementGroup", "managementGroupId", id)
} else {
managementGroupRoleAssignment := models.ManagementGroupRoleAssignment{
- ManagementGroupId: item.ParentId,
+ ManagementGroupId: id,
RoleAssignment: item.Ok,
}
log.V(2).Info("found managementGroup role assignment", "managementGroupRoleAssignment", managementGroupRoleAssignment)
diff --git a/cmd/list-management-group-role-assignments_test.go b/cmd/list-management-group-role-assignments_test.go
index eed6954..7f21669 100644
--- a/cmd/list-management-group-role-assignments_test.go
+++ b/cmd/list-management-group-role-assignments_test.go
@@ -22,6 +22,7 @@ import (
"fmt"
"testing"
+ "github.com/bloodhoundad/azurehound/v2/client"
"github.com/bloodhoundad/azurehound/v2/client/mocks"
"github.com/bloodhoundad/azurehound/v2/constants"
"github.com/bloodhoundad/azurehound/v2/models"
@@ -41,14 +42,14 @@ func TestListResourceGroupRoleAssignments(t *testing.T) {
mockClient := mocks.NewMockAzureClient(ctrl)
mockResourceGroupsChannel := make(chan interface{})
- mockResourceGroupRoleAssignmentChannel := make(chan azure.RoleAssignmentResult)
- mockResourceGroupRoleAssignmentChannel2 := make(chan azure.RoleAssignmentResult)
+ mockResourceGroupRoleAssignmentChannel := make(chan client.AzureResult[azure.RoleAssignment])
+ mockResourceGroupRoleAssignmentChannel2 := make(chan client.AzureResult[azure.RoleAssignment])
mockTenant := azure.Tenant{}
mockError := fmt.Errorf("I'm an error")
mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes()
- mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockResourceGroupRoleAssignmentChannel).Times(1)
- mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockResourceGroupRoleAssignmentChannel2).Times(1)
+ mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockResourceGroupRoleAssignmentChannel).Times(1)
+ mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockResourceGroupRoleAssignmentChannel2).Times(1)
channel := listResourceGroupRoleAssignments(ctx, mockClient, mockResourceGroupsChannel)
go func() {
@@ -62,14 +63,14 @@ func TestListResourceGroupRoleAssignments(t *testing.T) {
}()
go func() {
defer close(mockResourceGroupRoleAssignmentChannel)
- mockResourceGroupRoleAssignmentChannel <- azure.RoleAssignmentResult{
+ mockResourceGroupRoleAssignmentChannel <- client.AzureResult[azure.RoleAssignment]{
Ok: azure.RoleAssignment{
Properties: azure.RoleAssignmentPropertiesWithScope{
RoleDefinitionId: constants.ContributorRoleID,
},
},
}
- mockResourceGroupRoleAssignmentChannel <- azure.RoleAssignmentResult{
+ mockResourceGroupRoleAssignmentChannel <- client.AzureResult[azure.RoleAssignment]{
Ok: azure.RoleAssignment{
Properties: azure.RoleAssignmentPropertiesWithScope{
RoleDefinitionId: constants.OwnerRoleID,
@@ -79,14 +80,14 @@ func TestListResourceGroupRoleAssignments(t *testing.T) {
}()
go func() {
defer close(mockResourceGroupRoleAssignmentChannel2)
- mockResourceGroupRoleAssignmentChannel2 <- azure.RoleAssignmentResult{
+ mockResourceGroupRoleAssignmentChannel2 <- client.AzureResult[azure.RoleAssignment]{
Ok: azure.RoleAssignment{
Properties: azure.RoleAssignmentPropertiesWithScope{
RoleDefinitionId: constants.OwnerRoleID,
},
},
}
- mockResourceGroupRoleAssignmentChannel2 <- azure.RoleAssignmentResult{
+ mockResourceGroupRoleAssignmentChannel2 <- client.AzureResult[azure.RoleAssignment]{
Error: mockError,
}
}()
diff --git a/cmd/list-management-groups.go b/cmd/list-management-groups.go
index 87ddbe0..3af3019 100644
--- a/cmd/list-management-groups.go
+++ b/cmd/list-management-groups.go
@@ -66,7 +66,7 @@ func listManagementGroups(ctx context.Context, client client.AzureClient) <-chan
defer panicrecovery.PanicRecovery()
defer close(out)
count := 0
- for item := range client.ListAzureManagementGroups(ctx) {
+ for item := range client.ListAzureManagementGroups(ctx, "") {
if item.Error != nil {
log.Info("warning: unable to process azure management groups; either the organization has no management groups or azurehound does not have the reader role on the root management group.")
return
diff --git a/cmd/list-management-groups_test.go b/cmd/list-management-groups_test.go
index 47efe17..72f980c 100644
--- a/cmd/list-management-groups_test.go
+++ b/cmd/list-management-groups_test.go
@@ -22,6 +22,7 @@ import (
"fmt"
"testing"
+ "github.com/bloodhoundad/azurehound/v2/client"
"github.com/bloodhoundad/azurehound/v2/client/mocks"
"github.com/bloodhoundad/azurehound/v2/models/azure"
"go.uber.org/mock/gomock"
@@ -37,21 +38,21 @@ func TestListManagementGroups(t *testing.T) {
ctx := context.Background()
mockClient := mocks.NewMockAzureClient(ctrl)
- mockChannel := make(chan azure.ManagementGroupResult)
+ mockChannel := make(chan client.AzureResult[azure.ManagementGroup])
mockTenant := azure.Tenant{}
mockError := fmt.Errorf("I'm an error")
mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes()
- mockClient.EXPECT().ListAzureManagementGroups(gomock.Any()).Return(mockChannel)
+ mockClient.EXPECT().ListAzureManagementGroups(gomock.Any(), gomock.Any()).Return(mockChannel)
go func() {
defer close(mockChannel)
- mockChannel <- azure.ManagementGroupResult{
+ mockChannel <- client.AzureResult[azure.ManagementGroup]{
Ok: azure.ManagementGroup{},
}
- mockChannel <- azure.ManagementGroupResult{
+ mockChannel <- client.AzureResult[azure.ManagementGroup]{
Error: mockError,
}
- mockChannel <- azure.ManagementGroupResult{
+ mockChannel <- client.AzureResult[azure.ManagementGroup]{
Ok: azure.ManagementGroup{},
}
}()
diff --git a/cmd/list-resource-group-role-assignments.go b/cmd/list-resource-group-role-assignments.go
index a6d2fb7..dc10820 100644
--- a/cmd/list-resource-group-role-assignments.go
+++ b/cmd/list-resource-group-role-assignments.go
@@ -98,12 +98,12 @@ func listResourceGroupRoleAssignments(ctx context.Context, client client.AzureCl
}
count = 0
)
- for item := range client.ListRoleAssignmentsForResource(ctx, id, "") {
+ for item := range client.ListRoleAssignmentsForResource(ctx, id, "", "") {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing role assignments for this resourceGroup", "resourceGroupId", id)
} else {
resourceGroupRoleAssignment := models.ResourceGroupRoleAssignment{
- ResourceGroupId: item.ParentId,
+ ResourceGroupId: id,
RoleAssignment: item.Ok,
}
log.V(2).Info("found resourceGroup role assignment", "resourceGroupRoleAssignment", resourceGroupRoleAssignment)
diff --git a/cmd/list-resource-group-role-assignments_test.go b/cmd/list-resource-group-role-assignments_test.go
index 5c8c8bb..8b1ac8d 100644
--- a/cmd/list-resource-group-role-assignments_test.go
+++ b/cmd/list-resource-group-role-assignments_test.go
@@ -22,6 +22,7 @@ import (
"fmt"
"testing"
+ "github.com/bloodhoundad/azurehound/v2/client"
"github.com/bloodhoundad/azurehound/v2/client/mocks"
"github.com/bloodhoundad/azurehound/v2/constants"
"github.com/bloodhoundad/azurehound/v2/models"
@@ -41,14 +42,14 @@ func TestListManagementGroupRoleAssignments(t *testing.T) {
mockClient := mocks.NewMockAzureClient(ctrl)
mockManagementGroupsChannel := make(chan interface{})
- mockManagementGroupRoleAssignmentChannel := make(chan azure.RoleAssignmentResult)
- mockManagementGroupRoleAssignmentChannel2 := make(chan azure.RoleAssignmentResult)
+ mockManagementGroupRoleAssignmentChannel := make(chan client.AzureResult[azure.RoleAssignment])
+ mockManagementGroupRoleAssignmentChannel2 := make(chan client.AzureResult[azure.RoleAssignment])
mockTenant := azure.Tenant{}
mockError := fmt.Errorf("I'm an error")
mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes()
- mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockManagementGroupRoleAssignmentChannel).Times(1)
- mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockManagementGroupRoleAssignmentChannel2).Times(1)
+ mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockManagementGroupRoleAssignmentChannel).Times(1)
+ mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockManagementGroupRoleAssignmentChannel2).Times(1)
channel := listManagementGroupRoleAssignments(ctx, mockClient, mockManagementGroupsChannel)
go func() {
@@ -62,14 +63,14 @@ func TestListManagementGroupRoleAssignments(t *testing.T) {
}()
go func() {
defer close(mockManagementGroupRoleAssignmentChannel)
- mockManagementGroupRoleAssignmentChannel <- azure.RoleAssignmentResult{
+ mockManagementGroupRoleAssignmentChannel <- client.AzureResult[azure.RoleAssignment]{
Ok: azure.RoleAssignment{
Properties: azure.RoleAssignmentPropertiesWithScope{
RoleDefinitionId: constants.ContributorRoleID,
},
},
}
- mockManagementGroupRoleAssignmentChannel <- azure.RoleAssignmentResult{
+ mockManagementGroupRoleAssignmentChannel <- client.AzureResult[azure.RoleAssignment]{
Ok: azure.RoleAssignment{
Properties: azure.RoleAssignmentPropertiesWithScope{
RoleDefinitionId: constants.OwnerRoleID,
@@ -79,14 +80,14 @@ func TestListManagementGroupRoleAssignments(t *testing.T) {
}()
go func() {
defer close(mockManagementGroupRoleAssignmentChannel2)
- mockManagementGroupRoleAssignmentChannel2 <- azure.RoleAssignmentResult{
+ mockManagementGroupRoleAssignmentChannel2 <- client.AzureResult[azure.RoleAssignment]{
Ok: azure.RoleAssignment{
Properties: azure.RoleAssignmentPropertiesWithScope{
RoleDefinitionId: constants.OwnerRoleID,
},
},
}
- mockManagementGroupRoleAssignmentChannel2 <- azure.RoleAssignmentResult{
+ mockManagementGroupRoleAssignmentChannel2 <- client.AzureResult[azure.RoleAssignment]{
Error: mockError,
}
}()
diff --git a/cmd/list-resource-groups.go b/cmd/list-resource-groups.go
index c3ae948..c9b9516 100644
--- a/cmd/list-resource-groups.go
+++ b/cmd/list-resource-groups.go
@@ -26,6 +26,7 @@ import (
"time"
"github.com/bloodhoundad/azurehound/v2/client"
+ "github.com/bloodhoundad/azurehound/v2/client/query"
"github.com/bloodhoundad/azurehound/v2/enums"
"github.com/bloodhoundad/azurehound/v2/models"
"github.com/bloodhoundad/azurehound/v2/panicrecovery"
@@ -91,13 +92,13 @@ func listResourceGroups(ctx context.Context, client client.AzureClient, subscrip
defer wg.Done()
for id := range stream {
count := 0
- for item := range client.ListAzureResourceGroups(ctx, id, "") {
+ for item := range client.ListAzureResourceGroups(ctx, id, query.RMParams{Top: 1000}) {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing resource groups for this subscription", "subscriptionId", id)
} else {
resourceGroup := models.ResourceGroup{
ResourceGroup: item.Ok,
- SubscriptionId: item.SubscriptionId,
+ SubscriptionId: "/subscriptions/"+id,
TenantId: client.TenantInfo().TenantId,
}
log.V(2).Info("found resource group", "resourceGroup", resourceGroup)
diff --git a/cmd/list-resource-groups_test.go b/cmd/list-resource-groups_test.go
index 78ac328..19009a6 100644
--- a/cmd/list-resource-groups_test.go
+++ b/cmd/list-resource-groups_test.go
@@ -22,6 +22,7 @@ import (
"fmt"
"testing"
+ "github.com/bloodhoundad/azurehound/v2/client"
"github.com/bloodhoundad/azurehound/v2/client/mocks"
"github.com/bloodhoundad/azurehound/v2/models"
"github.com/bloodhoundad/azurehound/v2/models/azure"
@@ -40,8 +41,8 @@ func TestListResourceGroups(t *testing.T) {
mockClient := mocks.NewMockAzureClient(ctrl)
mockSubscriptionsChannel := make(chan interface{})
- mockResourceGroupChannel := make(chan azure.ResourceGroupResult)
- mockResourceGroupChannel2 := make(chan azure.ResourceGroupResult)
+ mockResourceGroupChannel := make(chan client.AzureResult[azure.ResourceGroup])
+ mockResourceGroupChannel2 := make(chan client.AzureResult[azure.ResourceGroup])
mockTenant := azure.Tenant{}
mockError := fmt.Errorf("I'm an error")
@@ -61,19 +62,19 @@ func TestListResourceGroups(t *testing.T) {
}()
go func() {
defer close(mockResourceGroupChannel)
- mockResourceGroupChannel <- azure.ResourceGroupResult{
+ mockResourceGroupChannel <- client.AzureResult[azure.ResourceGroup]{
Ok: azure.ResourceGroup{},
}
- mockResourceGroupChannel <- azure.ResourceGroupResult{
+ mockResourceGroupChannel <- client.AzureResult[azure.ResourceGroup]{
Ok: azure.ResourceGroup{},
}
}()
go func() {
defer close(mockResourceGroupChannel2)
- mockResourceGroupChannel2 <- azure.ResourceGroupResult{
+ mockResourceGroupChannel2 <- client.AzureResult[azure.ResourceGroup]{
Ok: azure.ResourceGroup{},
}
- mockResourceGroupChannel2 <- azure.ResourceGroupResult{
+ mockResourceGroupChannel2 <- client.AzureResult[azure.ResourceGroup]{
Error: mockError,
}
}()
diff --git a/cmd/list-role-assignments.go b/cmd/list-role-assignments.go
index 6e7ca32..b3248a4 100644
--- a/cmd/list-role-assignments.go
+++ b/cmd/list-role-assignments.go
@@ -26,6 +26,7 @@ import (
"time"
"github.com/bloodhoundad/azurehound/v2/client"
+ "github.com/bloodhoundad/azurehound/v2/client/query"
"github.com/bloodhoundad/azurehound/v2/enums"
"github.com/bloodhoundad/azurehound/v2/models"
"github.com/bloodhoundad/azurehound/v2/panicrecovery"
@@ -100,7 +101,7 @@ func listRoleAssignments(ctx context.Context, client client.AzureClient, roles <
filter = fmt.Sprintf("roleDefinitionId eq '%s'", id)
)
// We expand directoryScope in order to obtain the appId from app specific scoped role assignments
- for item := range client.ListAzureADRoleAssignments(ctx, filter, "", "", "directoryScope", nil) {
+ for item := range client.ListAzureADRoleAssignments(ctx, query.GraphParams{Filter: filter, Expand: "directoryScope"}) {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing role assignments for this role", "roleDefinitionId", id)
} else {
diff --git a/cmd/list-roles.go b/cmd/list-roles.go
index 836c9b5..7a377c6 100644
--- a/cmd/list-roles.go
+++ b/cmd/list-roles.go
@@ -24,6 +24,7 @@ import (
"time"
"github.com/bloodhoundad/azurehound/v2/client"
+ "github.com/bloodhoundad/azurehound/v2/client/query"
"github.com/bloodhoundad/azurehound/v2/enums"
"github.com/bloodhoundad/azurehound/v2/models"
"github.com/bloodhoundad/azurehound/v2/panicrecovery"
@@ -64,7 +65,7 @@ func listRoles(ctx context.Context, client client.AzureClient) <-chan interface{
defer panicrecovery.PanicRecovery()
defer close(out)
count := 0
- for item := range client.ListAzureADRoles(ctx, "", "") {
+ for item := range client.ListAzureADRoles(ctx, query.GraphParams{}) {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing roles")
return
diff --git a/cmd/list-roles_test.go b/cmd/list-roles_test.go
index 0805f0a..09cdcb5 100644
--- a/cmd/list-roles_test.go
+++ b/cmd/list-roles_test.go
@@ -22,6 +22,7 @@ import (
"fmt"
"testing"
+ "github.com/bloodhoundad/azurehound/v2/client"
"github.com/bloodhoundad/azurehound/v2/client/mocks"
"github.com/bloodhoundad/azurehound/v2/models/azure"
"go.uber.org/mock/gomock"
@@ -37,21 +38,21 @@ func TestListRoles(t *testing.T) {
ctx := context.Background()
mockClient := mocks.NewMockAzureClient(ctrl)
- mockChannel := make(chan azure.RoleResult)
+ mockChannel := make(chan client.AzureResult[azure.Role])
mockTenant := azure.Tenant{}
mockError := fmt.Errorf("I'm an error")
mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes()
- mockClient.EXPECT().ListAzureADRoles(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockChannel)
+ mockClient.EXPECT().ListAzureADRoles(gomock.Any(), gomock.Any()).Return(mockChannel)
go func() {
defer close(mockChannel)
- mockChannel <- azure.RoleResult{
+ mockChannel <- client.AzureResult[azure.Role]{
Ok: azure.Role{},
}
- mockChannel <- azure.RoleResult{
+ mockChannel <- client.AzureResult[azure.Role]{
Error: mockError,
}
- mockChannel <- azure.RoleResult{
+ mockChannel <- client.AzureResult[azure.Role]{
Ok: azure.Role{},
}
}()
diff --git a/cmd/list-service-principal-owners.go b/cmd/list-service-principal-owners.go
index 7fd4c56..7c13810 100644
--- a/cmd/list-service-principal-owners.go
+++ b/cmd/list-service-principal-owners.go
@@ -26,6 +26,7 @@ import (
"time"
"github.com/bloodhoundad/azurehound/v2/client"
+ "github.com/bloodhoundad/azurehound/v2/client/query"
"github.com/bloodhoundad/azurehound/v2/enums"
"github.com/bloodhoundad/azurehound/v2/models"
"github.com/bloodhoundad/azurehound/v2/panicrecovery"
@@ -96,13 +97,13 @@ func listServicePrincipalOwners(ctx context.Context, client client.AzureClient,
}
count = 0
)
- for item := range client.ListAzureADServicePrincipalOwners(ctx, id, "", "", "", nil) {
+ for item := range client.ListAzureADServicePrincipalOwners(ctx, id, query.GraphParams{}) {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing owners for this service principal", "servicePrincipalId", id)
} else {
servicePrincipalOwner := models.ServicePrincipalOwner{
Owner: item.Ok,
- ServicePrincipalId: item.ServicePrincipalId,
+ ServicePrincipalId: id,
}
log.V(2).Info("found service principal owner", "servicePrincipalOwner", servicePrincipalOwner)
count++
diff --git a/cmd/list-service-principal-owners_test.go b/cmd/list-service-principal-owners_test.go
index 1dff1d1..61f6eb5 100644
--- a/cmd/list-service-principal-owners_test.go
+++ b/cmd/list-service-principal-owners_test.go
@@ -23,6 +23,7 @@ import (
"fmt"
"testing"
+ "github.com/bloodhoundad/azurehound/v2/client"
"github.com/bloodhoundad/azurehound/v2/client/mocks"
"github.com/bloodhoundad/azurehound/v2/models"
"github.com/bloodhoundad/azurehound/v2/models/azure"
@@ -41,14 +42,14 @@ func TestListServicePrincipalOwners(t *testing.T) {
mockClient := mocks.NewMockAzureClient(ctrl)
mockServicePrincipalsChannel := make(chan interface{})
- mockServicePrincipalOwnerChannel := make(chan azure.ServicePrincipalOwnerResult)
- mockServicePrincipalOwnerChannel2 := make(chan azure.ServicePrincipalOwnerResult)
+ mockServicePrincipalOwnerChannel := make(chan client.AzureResult[json.RawMessage])
+ mockServicePrincipalOwnerChannel2 := make(chan client.AzureResult[json.RawMessage])
mockTenant := azure.Tenant{}
mockError := fmt.Errorf("I'm an error")
mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes()
- mockClient.EXPECT().ListAzureADServicePrincipalOwners(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockServicePrincipalOwnerChannel).Times(1)
- mockClient.EXPECT().ListAzureADServicePrincipalOwners(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockServicePrincipalOwnerChannel2).Times(1)
+ mockClient.EXPECT().ListAzureADServicePrincipalOwners(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockServicePrincipalOwnerChannel).Times(1)
+ mockClient.EXPECT().ListAzureADServicePrincipalOwners(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockServicePrincipalOwnerChannel2).Times(1)
channel := listServicePrincipalOwners(ctx, mockClient, mockServicePrincipalsChannel)
go func() {
@@ -62,19 +63,19 @@ func TestListServicePrincipalOwners(t *testing.T) {
}()
go func() {
defer close(mockServicePrincipalOwnerChannel)
- mockServicePrincipalOwnerChannel <- azure.ServicePrincipalOwnerResult{
+ mockServicePrincipalOwnerChannel <- client.AzureResult[json.RawMessage]{
Ok: json.RawMessage{},
}
- mockServicePrincipalOwnerChannel <- azure.ServicePrincipalOwnerResult{
+ mockServicePrincipalOwnerChannel <- client.AzureResult[json.RawMessage]{
Ok: json.RawMessage{},
}
}()
go func() {
defer close(mockServicePrincipalOwnerChannel2)
- mockServicePrincipalOwnerChannel2 <- azure.ServicePrincipalOwnerResult{
+ mockServicePrincipalOwnerChannel2 <- client.AzureResult[json.RawMessage]{
Ok: json.RawMessage{},
}
- mockServicePrincipalOwnerChannel2 <- azure.ServicePrincipalOwnerResult{
+ mockServicePrincipalOwnerChannel2 <- client.AzureResult[json.RawMessage]{
Error: mockError,
}
}()
diff --git a/cmd/list-service-principals.go b/cmd/list-service-principals.go
index 57399bd..5d427af 100644
--- a/cmd/list-service-principals.go
+++ b/cmd/list-service-principals.go
@@ -24,6 +24,7 @@ import (
"time"
"github.com/bloodhoundad/azurehound/v2/client"
+ "github.com/bloodhoundad/azurehound/v2/client/query"
"github.com/bloodhoundad/azurehound/v2/enums"
"github.com/bloodhoundad/azurehound/v2/models"
"github.com/bloodhoundad/azurehound/v2/panicrecovery"
@@ -64,7 +65,7 @@ func listServicePrincipals(ctx context.Context, client client.AzureClient) <-cha
defer panicrecovery.PanicRecovery()
defer close(out)
count := 0
- for item := range client.ListAzureADServicePrincipals(ctx, "", "", "", "", nil) {
+ for item := range client.ListAzureADServicePrincipals(ctx, query.GraphParams{}) {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing service principals")
return
diff --git a/cmd/list-service-principals_test.go b/cmd/list-service-principals_test.go
index c62f028..b9058fa 100644
--- a/cmd/list-service-principals_test.go
+++ b/cmd/list-service-principals_test.go
@@ -22,6 +22,7 @@ import (
"fmt"
"testing"
+ "github.com/bloodhoundad/azurehound/v2/client"
"github.com/bloodhoundad/azurehound/v2/client/mocks"
"github.com/bloodhoundad/azurehound/v2/models/azure"
"go.uber.org/mock/gomock"
@@ -37,21 +38,21 @@ func TestListServicePrincipals(t *testing.T) {
ctx := context.Background()
mockClient := mocks.NewMockAzureClient(ctrl)
- mockChannel := make(chan azure.ServicePrincipalResult)
+ mockChannel := make(chan client.AzureResult[azure.ServicePrincipal])
mockTenant := azure.Tenant{}
mockError := fmt.Errorf("I'm an error")
mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes()
- mockClient.EXPECT().ListAzureADServicePrincipals(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockChannel)
+ mockClient.EXPECT().ListAzureADServicePrincipals(gomock.Any(), gomock.Any()).Return(mockChannel)
go func() {
defer close(mockChannel)
- mockChannel <- azure.ServicePrincipalResult{
+ mockChannel <- client.AzureResult[azure.ServicePrincipal]{
Ok: azure.ServicePrincipal{},
}
- mockChannel <- azure.ServicePrincipalResult{
+ mockChannel <- client.AzureResult[azure.ServicePrincipal]{
Error: mockError,
}
- mockChannel <- azure.ServicePrincipalResult{
+ mockChannel <- client.AzureResult[azure.ServicePrincipal]{
Ok: azure.ServicePrincipal{},
}
}()
diff --git a/cmd/list-storage-account-role-assignments.go b/cmd/list-storage-account-role-assignments.go
index 71df35a..a1b2546 100644
--- a/cmd/list-storage-account-role-assignments.go
+++ b/cmd/list-storage-account-role-assignments.go
@@ -98,7 +98,7 @@ func listStorageAccountRoleAssignments(ctx context.Context, client client.AzureC
}
count = 0
)
- for item := range client.ListRoleAssignmentsForResource(ctx, id, "") {
+ for item := range client.ListRoleAssignmentsForResource(ctx, id, "", "") {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing role assignments for this storage account", "storageAccountId", id)
} else {
@@ -106,7 +106,7 @@ func listStorageAccountRoleAssignments(ctx context.Context, client client.AzureC
storageAccountRoleAssignment := models.AzureRoleAssignment{
Assignee: item.Ok,
- ObjectId: item.ParentId,
+ ObjectId: id,
RoleDefinitionId: roleDefinitionId,
}
log.V(2).Info("found storage account role assignment", "storageAccountRoleAssignment", storageAccountRoleAssignment)
diff --git a/cmd/list-storage-accounts.go b/cmd/list-storage-accounts.go
index 8c91c71..000ae9c 100644
--- a/cmd/list-storage-accounts.go
+++ b/cmd/list-storage-accounts.go
@@ -94,13 +94,11 @@ func listStorageAccounts(ctx context.Context, client client.AzureClient, subscri
if item.Error != nil {
log.Error(item.Error, "unable to continue processing storage accounts for this subscription", "subscriptionId", id)
} else {
- resourceGroupId := item.Ok.ResourceGroupId()
- resourceGroupName := item.Ok.ResourceGroupName()
storageAccount := models.StorageAccount{
StorageAccount: item.Ok,
- SubscriptionId: item.SubscriptionId,
- ResourceGroupId: resourceGroupId,
- ResourceGroupName: resourceGroupName,
+ SubscriptionId: "/subscriptions/" + id,
+ ResourceGroupId: item.Ok.ResourceGroupId(),
+ ResourceGroupName: item.Ok.ResourceGroupName(),
TenantId: client.TenantInfo().TenantId,
}
log.V(2).Info("found storage account", "storageAccount", storageAccount)
diff --git a/cmd/list-storage-containers.go b/cmd/list-storage-containers.go
index 322f456..ff0a494 100644
--- a/cmd/list-storage-containers.go
+++ b/cmd/list-storage-containers.go
@@ -101,14 +101,12 @@ func listStorageContainers(ctx context.Context, client client.AzureClient, stora
if item.Error != nil {
log.Error(item.Error, "unable to continue processing storage containers for this subscription", "subscriptionId", stAccount.(models.StorageAccount).SubscriptionId, "storageAccountName", stAccount.(models.StorageAccount).Name)
} else {
- resourceGroupId := item.Ok.ResourceGroupId()
- resourceGroupName := item.Ok.ResourceGroupName()
storageContainer := models.StorageContainer{
StorageContainer: item.Ok,
StorageAccountId: stAccount.(models.StorageAccount).StorageAccount.Id,
- SubscriptionId: item.SubscriptionId,
- ResourceGroupId: resourceGroupId,
- ResourceGroupName: resourceGroupName,
+ SubscriptionId: "/subscriptions/"+stAccount.(models.StorageAccount).SubscriptionId,
+ ResourceGroupId: item.Ok.ResourceGroupId(),
+ ResourceGroupName: item.Ok.ResourceGroupName(),
TenantId: client.TenantInfo().TenantId,
}
log.V(2).Info("found storage container", "storageContainer", storageContainer)
diff --git a/cmd/list-subscription-role-assignments.go b/cmd/list-subscription-role-assignments.go
index 94279e3..b23421e 100644
--- a/cmd/list-subscription-role-assignments.go
+++ b/cmd/list-subscription-role-assignments.go
@@ -97,12 +97,12 @@ func listSubscriptionRoleAssignments(ctx context.Context, client client.AzureCli
}
count = 0
)
- for item := range client.ListRoleAssignmentsForResource(ctx, id, "atScope()") {
+ for item := range client.ListRoleAssignmentsForResource(ctx, id, "atScope()", "") {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing role assignments for this subscription", "subscriptionId", id)
} else {
subscriptionRoleAssignment := models.SubscriptionRoleAssignment{
- SubscriptionId: item.ParentId,
+ SubscriptionId: id,
RoleAssignment: item.Ok,
}
log.V(2).Info("found subscription role assignment", "subscriptionRoleAssignment", subscriptionRoleAssignment)
diff --git a/cmd/list-subscription-role-assignments_test.go b/cmd/list-subscription-role-assignments_test.go
index 1902684..73a74d8 100644
--- a/cmd/list-subscription-role-assignments_test.go
+++ b/cmd/list-subscription-role-assignments_test.go
@@ -22,6 +22,7 @@ import (
"fmt"
"testing"
+ "github.com/bloodhoundad/azurehound/v2/client"
"github.com/bloodhoundad/azurehound/v2/client/mocks"
"github.com/bloodhoundad/azurehound/v2/constants"
"github.com/bloodhoundad/azurehound/v2/models"
@@ -41,14 +42,14 @@ func TestListSubscriptionRoleAssignments(t *testing.T) {
mockClient := mocks.NewMockAzureClient(ctrl)
mockSubscriptionsChannel := make(chan interface{})
- mockSubscriptionRoleAssignmentChannel := make(chan azure.RoleAssignmentResult)
- mockSubscriptionRoleAssignmentChannel2 := make(chan azure.RoleAssignmentResult)
+ mockSubscriptionRoleAssignmentChannel := make(chan client.AzureResult[azure.RoleAssignment])
+ mockSubscriptionRoleAssignmentChannel2 := make(chan client.AzureResult[azure.RoleAssignment])
mockTenant := azure.Tenant{}
mockError := fmt.Errorf("I'm an error")
mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes()
- mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockSubscriptionRoleAssignmentChannel).Times(1)
- mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockSubscriptionRoleAssignmentChannel2).Times(1)
+ mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockSubscriptionRoleAssignmentChannel).Times(1)
+ mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockSubscriptionRoleAssignmentChannel2).Times(1)
channel := listSubscriptionRoleAssignments(ctx, mockClient, mockSubscriptionsChannel)
go func() {
@@ -62,14 +63,14 @@ func TestListSubscriptionRoleAssignments(t *testing.T) {
}()
go func() {
defer close(mockSubscriptionRoleAssignmentChannel)
- mockSubscriptionRoleAssignmentChannel <- azure.RoleAssignmentResult{
+ mockSubscriptionRoleAssignmentChannel <- client.AzureResult[azure.RoleAssignment]{
Ok: azure.RoleAssignment{
Properties: azure.RoleAssignmentPropertiesWithScope{
RoleDefinitionId: constants.ContributorRoleID,
},
},
}
- mockSubscriptionRoleAssignmentChannel <- azure.RoleAssignmentResult{
+ mockSubscriptionRoleAssignmentChannel <- client.AzureResult[azure.RoleAssignment]{
Ok: azure.RoleAssignment{
Properties: azure.RoleAssignmentPropertiesWithScope{
RoleDefinitionId: constants.OwnerRoleID,
@@ -79,14 +80,14 @@ func TestListSubscriptionRoleAssignments(t *testing.T) {
}()
go func() {
defer close(mockSubscriptionRoleAssignmentChannel2)
- mockSubscriptionRoleAssignmentChannel2 <- azure.RoleAssignmentResult{
+ mockSubscriptionRoleAssignmentChannel2 <- client.AzureResult[azure.RoleAssignment]{
Ok: azure.RoleAssignment{
Properties: azure.RoleAssignmentPropertiesWithScope{
RoleDefinitionId: constants.OwnerRoleID,
},
},
}
- mockSubscriptionRoleAssignmentChannel2 <- azure.RoleAssignmentResult{
+ mockSubscriptionRoleAssignmentChannel2 <- client.AzureResult[azure.RoleAssignment]{
Error: mockError,
}
}()
diff --git a/cmd/list-subscriptions_test.go b/cmd/list-subscriptions_test.go
index 51571c5..3e9f8be 100644
--- a/cmd/list-subscriptions_test.go
+++ b/cmd/list-subscriptions_test.go
@@ -22,6 +22,7 @@ import (
"fmt"
"testing"
+ "github.com/bloodhoundad/azurehound/v2/client"
"github.com/bloodhoundad/azurehound/v2/client/mocks"
"github.com/bloodhoundad/azurehound/v2/models/azure"
"go.uber.org/mock/gomock"
@@ -37,7 +38,7 @@ func TestListSubscriptions(t *testing.T) {
ctx := context.Background()
mockClient := mocks.NewMockAzureClient(ctrl)
- mockChannel := make(chan azure.SubscriptionResult)
+ mockChannel := make(chan client.AzureResult[azure.Subscription])
mockTenant := azure.Tenant{}
mockError := fmt.Errorf("I'm an error")
mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes()
@@ -45,13 +46,13 @@ func TestListSubscriptions(t *testing.T) {
go func() {
defer close(mockChannel)
- mockChannel <- azure.SubscriptionResult{
+ mockChannel <- client.AzureResult[azure.Subscription]{
Ok: azure.Subscription{},
}
- mockChannel <- azure.SubscriptionResult{
+ mockChannel <- client.AzureResult[azure.Subscription]{
Error: mockError,
}
- mockChannel <- azure.SubscriptionResult{
+ mockChannel <- client.AzureResult[azure.Subscription]{
Ok: azure.Subscription{},
}
}()
diff --git a/cmd/list-tenants_test.go b/cmd/list-tenants_test.go
index 5f22399..c0648e3 100644
--- a/cmd/list-tenants_test.go
+++ b/cmd/list-tenants_test.go
@@ -22,6 +22,7 @@ import (
"fmt"
"testing"
+ "github.com/bloodhoundad/azurehound/v2/client"
"github.com/bloodhoundad/azurehound/v2/client/mocks"
"github.com/bloodhoundad/azurehound/v2/models/azure"
"go.uber.org/mock/gomock"
@@ -37,7 +38,7 @@ func TestListTenants(t *testing.T) {
ctx := context.Background()
mockClient := mocks.NewMockAzureClient(ctrl)
- mockChannel := make(chan azure.TenantResult)
+ mockChannel := make(chan client.AzureResult[azure.Tenant])
mockTenant := azure.Tenant{}
mockError := fmt.Errorf("I'm an error")
mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes()
@@ -45,13 +46,13 @@ func TestListTenants(t *testing.T) {
go func() {
defer close(mockChannel)
- mockChannel <- azure.TenantResult{
+ mockChannel <- client.AzureResult[azure.Tenant]{
Ok: azure.Tenant{},
}
- mockChannel <- azure.TenantResult{
+ mockChannel <- client.AzureResult[azure.Tenant]{
Error: mockError,
}
- mockChannel <- azure.TenantResult{
+ mockChannel <- client.AzureResult[azure.Tenant]{
Ok: azure.Tenant{},
}
}()
diff --git a/cmd/list-users.go b/cmd/list-users.go
index 531b7a3..be94d8a 100644
--- a/cmd/list-users.go
+++ b/cmd/list-users.go
@@ -24,6 +24,7 @@ import (
"time"
"github.com/bloodhoundad/azurehound/v2/client"
+ "github.com/bloodhoundad/azurehound/v2/client/query"
"github.com/bloodhoundad/azurehound/v2/enums"
"github.com/bloodhoundad/azurehound/v2/models"
"github.com/bloodhoundad/azurehound/v2/panicrecovery"
@@ -42,7 +43,7 @@ var listUsersCmd = &cobra.Command{
SilenceUsage: true,
}
-func listUsersCmdImpl(cmd *cobra.Command, args []string) {
+func listUsersCmdImpl(cmd *cobra.Command, _ []string) {
ctx, stop := signal.NotifyContext(cmd.Context(), os.Interrupt, os.Kill)
defer gracefulShutdown(stop)
@@ -60,23 +61,25 @@ func listUsersCmdImpl(cmd *cobra.Command, args []string) {
func listUsers(ctx context.Context, client client.AzureClient) <-chan interface{} {
out := make(chan interface{})
+ params := query.GraphParams{Select: []string{
+ "accountEnabled",
+ "createdDateTime",
+ "displayName",
+ "jobTitle",
+ "lastPasswordChangeDateTime",
+ "mail",
+ "onPremisesSecurityIdentifier",
+ "onPremisesSyncEnabled",
+ "userPrincipalName",
+ "userType",
+ "id",
+ }}
+
go func() {
defer panicrecovery.PanicRecovery()
defer close(out)
count := 0
- for item := range client.ListAzureADUsers(ctx, "", "", "", []string{
- "accountEnabled",
- "createdDateTime",
- "displayName",
- "jobTitle",
- "lastPasswordChangeDateTime",
- "mail",
- "onPremisesSecurityIdentifier",
- "onPremisesSyncEnabled",
- "userPrincipalName",
- "userType",
- "id",
- }) {
+ for item := range client.ListAzureADUsers(ctx, params) {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing users")
return
diff --git a/cmd/list-users_test.go b/cmd/list-users_test.go
index d7e6211..59028e0 100644
--- a/cmd/list-users_test.go
+++ b/cmd/list-users_test.go
@@ -22,6 +22,7 @@ import (
"fmt"
"testing"
+ "github.com/bloodhoundad/azurehound/v2/client"
"github.com/bloodhoundad/azurehound/v2/client/mocks"
"github.com/bloodhoundad/azurehound/v2/models/azure"
"go.uber.org/mock/gomock"
@@ -38,21 +39,21 @@ func TestListUsers(t *testing.T) {
ctx := context.Background()
mockClient := mocks.NewMockAzureClient(ctrl)
- mockChannel := make(chan azure.UserResult)
+ mockChannel := make(chan client.AzureResult[azure.User])
mockTenant := azure.Tenant{}
mockError := fmt.Errorf("I'm an error")
mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes()
- mockClient.EXPECT().ListAzureADUsers(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockChannel)
+ mockClient.EXPECT().ListAzureADUsers(gomock.Any(), gomock.Any()).Return(mockChannel)
go func() {
defer close(mockChannel)
- mockChannel <- azure.UserResult{
+ mockChannel <- client.AzureResult[azure.User]{
Ok: azure.User{},
}
- mockChannel <- azure.UserResult{
+ mockChannel <- client.AzureResult[azure.User]{
Error: mockError,
}
- mockChannel <- azure.UserResult{
+ mockChannel <- client.AzureResult[azure.User]{
Ok: azure.User{},
}
}()
diff --git a/cmd/list-virtual-machine-role-assignments.go b/cmd/list-virtual-machine-role-assignments.go
index 097055e..389cafd 100644
--- a/cmd/list-virtual-machine-role-assignments.go
+++ b/cmd/list-virtual-machine-role-assignments.go
@@ -97,12 +97,12 @@ func listVirtualMachineRoleAssignments(ctx context.Context, client client.AzureC
}
count = 0
)
- for item := range client.ListRoleAssignmentsForResource(ctx, id, "") {
+ for item := range client.ListRoleAssignmentsForResource(ctx, id, "", "") {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing role assignments for this virtual machine", "virtualMachineId", id)
} else {
virtualMachineRoleAssignment := models.VirtualMachineRoleAssignment{
- VirtualMachineId: item.ParentId,
+ VirtualMachineId: id,
RoleAssignment: item.Ok,
}
log.V(2).Info("found virtual machine role assignment", "virtualMachineRoleAssignment", virtualMachineRoleAssignment)
diff --git a/cmd/list-virtual-machine-role-assignments_test.go b/cmd/list-virtual-machine-role-assignments_test.go
index dffaf79..efd5112 100644
--- a/cmd/list-virtual-machine-role-assignments_test.go
+++ b/cmd/list-virtual-machine-role-assignments_test.go
@@ -22,6 +22,7 @@ import (
"fmt"
"testing"
+ "github.com/bloodhoundad/azurehound/v2/client"
"github.com/bloodhoundad/azurehound/v2/client/mocks"
"github.com/bloodhoundad/azurehound/v2/constants"
"github.com/bloodhoundad/azurehound/v2/models"
@@ -41,14 +42,14 @@ func TestListVirtualMachineRoleAssignments(t *testing.T) {
mockClient := mocks.NewMockAzureClient(ctrl)
mockVirtualMachinesChannel := make(chan interface{})
- mockVirtualMachineRoleAssignmentChannel := make(chan azure.RoleAssignmentResult)
- mockVirtualMachineRoleAssignmentChannel2 := make(chan azure.RoleAssignmentResult)
+ mockVirtualMachineRoleAssignmentChannel := make(chan client.AzureResult[azure.RoleAssignment])
+ mockVirtualMachineRoleAssignmentChannel2 := make(chan client.AzureResult[azure.RoleAssignment])
mockTenant := azure.Tenant{}
mockError := fmt.Errorf("I'm an error")
mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes()
- mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockVirtualMachineRoleAssignmentChannel).Times(1)
- mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockVirtualMachineRoleAssignmentChannel2).Times(1)
+ mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockVirtualMachineRoleAssignmentChannel).Times(1)
+ mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockVirtualMachineRoleAssignmentChannel2).Times(1)
channel := listVirtualMachineRoleAssignments(ctx, mockClient, mockVirtualMachinesChannel)
go func() {
@@ -62,14 +63,14 @@ func TestListVirtualMachineRoleAssignments(t *testing.T) {
}()
go func() {
defer close(mockVirtualMachineRoleAssignmentChannel)
- mockVirtualMachineRoleAssignmentChannel <- azure.RoleAssignmentResult{
+ mockVirtualMachineRoleAssignmentChannel <- client.AzureResult[azure.RoleAssignment]{
Ok: azure.RoleAssignment{
Properties: azure.RoleAssignmentPropertiesWithScope{
RoleDefinitionId: constants.VirtualMachineContributorRoleID,
},
},
}
- mockVirtualMachineRoleAssignmentChannel <- azure.RoleAssignmentResult{
+ mockVirtualMachineRoleAssignmentChannel <- client.AzureResult[azure.RoleAssignment]{
Ok: azure.RoleAssignment{
Properties: azure.RoleAssignmentPropertiesWithScope{
RoleDefinitionId: constants.AvereContributorRoleID,
@@ -79,14 +80,14 @@ func TestListVirtualMachineRoleAssignments(t *testing.T) {
}()
go func() {
defer close(mockVirtualMachineRoleAssignmentChannel2)
- mockVirtualMachineRoleAssignmentChannel2 <- azure.RoleAssignmentResult{
+ mockVirtualMachineRoleAssignmentChannel2 <- client.AzureResult[azure.RoleAssignment]{
Ok: azure.RoleAssignment{
Properties: azure.RoleAssignmentPropertiesWithScope{
RoleDefinitionId: constants.VirtualMachineAdministratorLoginRoleID,
},
},
}
- mockVirtualMachineRoleAssignmentChannel2 <- azure.RoleAssignmentResult{
+ mockVirtualMachineRoleAssignmentChannel2 <- client.AzureResult[azure.RoleAssignment]{
Error: mockError,
}
}()
diff --git a/cmd/list-virtual-machines.go b/cmd/list-virtual-machines.go
index d28d6e5..6e4c77e 100644
--- a/cmd/list-virtual-machines.go
+++ b/cmd/list-virtual-machines.go
@@ -26,6 +26,7 @@ import (
"time"
"github.com/bloodhoundad/azurehound/v2/client"
+ "github.com/bloodhoundad/azurehound/v2/client/query"
"github.com/bloodhoundad/azurehound/v2/enums"
"github.com/bloodhoundad/azurehound/v2/models"
"github.com/bloodhoundad/azurehound/v2/panicrecovery"
@@ -90,15 +91,14 @@ func listVirtualMachines(ctx context.Context, client client.AzureClient, subscri
defer wg.Done()
for id := range stream {
count := 0
- for item := range client.ListAzureVirtualMachines(ctx, id, false) {
+ for item := range client.ListAzureVirtualMachines(ctx, id, query.RMParams{}) {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing virtual machines for this subscription", "subscriptionId", id)
} else {
- resourceGroupId := item.Ok.ResourceGroupId()
virtualMachine := models.VirtualMachine{
VirtualMachine: item.Ok,
- SubscriptionId: item.SubscriptionId,
- ResourceGroupId: resourceGroupId,
+ SubscriptionId: "/subscriptions/" + id,
+ ResourceGroupId: item.Ok.ResourceGroupId(),
TenantId: client.TenantInfo().TenantId,
}
log.V(2).Info("found virtual machine", "virtualMachine", virtualMachine)
diff --git a/cmd/list-virtual-machines_test.go b/cmd/list-virtual-machines_test.go
index 58b9113..b955d84 100644
--- a/cmd/list-virtual-machines_test.go
+++ b/cmd/list-virtual-machines_test.go
@@ -22,6 +22,7 @@ import (
"fmt"
"testing"
+ "github.com/bloodhoundad/azurehound/v2/client"
"github.com/bloodhoundad/azurehound/v2/client/mocks"
"github.com/bloodhoundad/azurehound/v2/models"
"github.com/bloodhoundad/azurehound/v2/models/azure"
@@ -40,8 +41,8 @@ func TestListVirtualMachines(t *testing.T) {
mockClient := mocks.NewMockAzureClient(ctrl)
mockSubscriptionsChannel := make(chan interface{})
- mockVirtualMachineChannel := make(chan azure.VirtualMachineResult)
- mockVirtualMachineChannel2 := make(chan azure.VirtualMachineResult)
+ mockVirtualMachineChannel := make(chan client.AzureResult[azure.VirtualMachine])
+ mockVirtualMachineChannel2 := make(chan client.AzureResult[azure.VirtualMachine])
mockTenant := azure.Tenant{}
mockError := fmt.Errorf("I'm an error")
@@ -61,19 +62,19 @@ func TestListVirtualMachines(t *testing.T) {
}()
go func() {
defer close(mockVirtualMachineChannel)
- mockVirtualMachineChannel <- azure.VirtualMachineResult{
+ mockVirtualMachineChannel <- client.AzureResult[azure.VirtualMachine]{
Ok: azure.VirtualMachine{},
}
- mockVirtualMachineChannel <- azure.VirtualMachineResult{
+ mockVirtualMachineChannel <- client.AzureResult[azure.VirtualMachine]{
Ok: azure.VirtualMachine{},
}
}()
go func() {
defer close(mockVirtualMachineChannel2)
- mockVirtualMachineChannel2 <- azure.VirtualMachineResult{
+ mockVirtualMachineChannel2 <- client.AzureResult[azure.VirtualMachine]{
Ok: azure.VirtualMachine{},
}
- mockVirtualMachineChannel2 <- azure.VirtualMachineResult{
+ mockVirtualMachineChannel2 <- client.AzureResult[azure.VirtualMachine]{
Error: mockError,
}
}()
diff --git a/cmd/list-vm-scale-set-role-assignments.go b/cmd/list-vm-scale-set-role-assignments.go
index 4a82b2e..34841c9 100644
--- a/cmd/list-vm-scale-set-role-assignments.go
+++ b/cmd/list-vm-scale-set-role-assignments.go
@@ -103,7 +103,7 @@ func listVMScaleSetRoleAssignments(ctx context.Context, client client.AzureClien
}
count = 0
)
- for item := range client.ListRoleAssignmentsForResource(ctx, id, "") {
+ for item := range client.ListRoleAssignmentsForResource(ctx, id, "", "") {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing role assignments for this vm scale set", "vmScaleSetId", id)
} else {
@@ -111,7 +111,7 @@ func listVMScaleSetRoleAssignments(ctx context.Context, client client.AzureClien
vmScaleSetRoleAssignment := models.AzureRoleAssignment{
Assignee: item.Ok,
- ObjectId: item.ParentId,
+ ObjectId: id,
RoleDefinitionId: roleDefinitionId,
}
log.V(2).Info("found vm scale set role assignment", "vmScaleSetRoleAssignment", vmScaleSetRoleAssignment)
diff --git a/cmd/list-vm-scale-sets.go b/cmd/list-vm-scale-sets.go
index c55f4b2..2ace333 100644
--- a/cmd/list-vm-scale-sets.go
+++ b/cmd/list-vm-scale-sets.go
@@ -96,15 +96,14 @@ func listVMScaleSets(ctx context.Context, client client.AzureClient, subscriptio
defer wg.Done()
for id := range stream {
count := 0
- for item := range client.ListAzureVMScaleSets(ctx, id, false) {
+ for item := range client.ListAzureVMScaleSets(ctx, id) {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing virtual machine scale sets for this subscription", "subscriptionId", id)
} else {
- resourceGroupId := item.Ok.ResourceGroupId()
vmScaleSet := models.VMScaleSet{
VMScaleSet: item.Ok,
- SubscriptionId: item.SubscriptionId,
- ResourceGroupId: resourceGroupId,
+ SubscriptionId: "/subscriptions/"+id,
+ ResourceGroupId: item.Ok.ResourceGroupId(),
TenantId: client.TenantInfo().TenantId,
}
log.V(2).Info("found virtual machine scale set", "vmScaleSet", vmScaleSet)
diff --git a/cmd/list-web-app-role-assignments.go b/cmd/list-web-app-role-assignments.go
index 90ce0ef..e4d41c2 100644
--- a/cmd/list-web-app-role-assignments.go
+++ b/cmd/list-web-app-role-assignments.go
@@ -103,7 +103,7 @@ func listWebAppRoleAssignments(ctx context.Context, client client.AzureClient, w
}
count = 0
)
- for item := range client.ListRoleAssignmentsForResource(ctx, id, "") {
+ for item := range client.ListRoleAssignmentsForResource(ctx, id, "", "") {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing role assignments for this web app", "webAppId", id)
} else {
@@ -111,7 +111,7 @@ func listWebAppRoleAssignments(ctx context.Context, client client.AzureClient, w
webAppRoleAssignment := models.AzureRoleAssignment{
Assignee: item.Ok,
- ObjectId: item.ParentId,
+ ObjectId: id,
RoleDefinitionId: roleDefinitionId,
}
log.V(2).Info("Found web app role asignment", "webAppRoleAssignment", webAppRoleAssignment)
diff --git a/cmd/list-web-apps.go b/cmd/list-web-apps.go
index ac2aaec..ec53067 100644
--- a/cmd/list-web-apps.go
+++ b/cmd/list-web-apps.go
@@ -99,12 +99,12 @@ func listWebApps(ctx context.Context, client client.AzureClient, subscriptions <
if item.Error != nil {
log.Error(item.Error, "unable to continue processing web apps for this subscription", "subscriptionId", id)
} else {
- resourceGroupId := item.Ok.ResourceGroupId()
webApp := models.WebApp{
- WebApp: item.Ok,
- SubscriptionId: item.SubscriptionId,
- ResourceGroupId: resourceGroupId,
- TenantId: client.TenantInfo().TenantId,
+ WebApp: item.Ok,
+ SubscriptionId: "/subscriptions/" + id,
+ ResourceGroupId: item.Ok.ResourceGroupId(),
+ ResourceGroupName: item.Ok.ResourceGroupName(),
+ TenantId: client.TenantInfo().TenantId,
}
if webApp.Kind == "app" {
log.V(2).Info("found web app", "webApp", webApp)
diff --git a/go.mod b/go.mod
index f364545..7ac6e40 100644
--- a/go.mod
+++ b/go.mod
@@ -9,7 +9,7 @@ require (
github.com/judwhite/go-svc v1.2.1
github.com/manifoldco/promptui v0.9.0
github.com/rs/zerolog v1.26.0
- github.com/spf13/cobra v1.3.0
+ github.com/spf13/cobra v1.8.1
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.10.1
github.com/stretchr/testify v1.7.0
@@ -24,7 +24,7 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fsnotify/fsnotify v1.5.1 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
- github.com/inconshreveable/mousetrap v1.0.0 // indirect
+ github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/magiconair/properties v1.8.5 // indirect
github.com/mitchellh/mapstructure v1.4.3 // indirect
github.com/pelletier/go-toml v1.9.4 // indirect
@@ -34,8 +34,10 @@ require (
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/subosito/gotenv v1.2.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
+ golang.org/x/mod v0.8.0 // indirect
golang.org/x/text v0.14.0 // indirect
+ golang.org/x/tools v0.6.0 // indirect
gopkg.in/ini.v1 v1.66.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
- gopkg.in/yaml.v3 v3.0.0 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/go.sum b/go.sum
index bbbb2cb..caf00fb 100644
--- a/go.sum
+++ b/go.sum
@@ -91,6 +91,7 @@ github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWH
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -236,6 +237,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
+github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@@ -332,6 +335,8 @@ github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA=
github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v1.3.0 h1:R7cSvGu+Vv+qX0gW5R/85dx2kmmJT5z5NM8ifdYjdn0=
github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4=
+github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
+github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
@@ -424,6 +429,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
+golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -636,6 +643,8 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
+golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -784,6 +793,7 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
@@ -803,6 +813,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA=
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/models/azure/app_role_assignment.go b/models/azure/app_role_assignment.go
index 59c0234..708a4d8 100644
--- a/models/azure/app_role_assignment.go
+++ b/models/azure/app_role_assignment.go
@@ -37,15 +37,3 @@ type AppRoleAssignment struct {
ResourceDisplayName string `json:"resourceDisplayName,omitempty"`
ResourceId string `json:"resourceId,omitempty"`
}
-
-type AppRoleAssignmentList struct {
- Count int `json:"@odata.count,omitempty"` // The total count of all results
- NextLink string `json:"@odata.nextLink,omitempty"` // The URL to use for getting the next set of values.
- Context string `json:"@odata.context,omitempty"`
- Value []AppRoleAssignment `json:"value"` // A list of role assignments.
-}
-
-type AppRoleAssignmentResult struct {
- Error error
- Ok AppRoleAssignment
-}
diff --git a/models/azure/application.go b/models/azure/application.go
index cec69cf..a44a103 100644
--- a/models/azure/application.go
+++ b/models/azure/application.go
@@ -17,8 +17,6 @@
package azure
-import "encoding/json"
-
// Represents an application. Any application that outsources authentication to Azure Active Directory (Azure AD) must
// be registered in a directory. Application registration involves telling Azure AD about your application, including
// the URL where it's located, the URL to send replies after authentication, the URI to identify your application, and
@@ -171,20 +169,3 @@ type Application struct {
// Specifies settings for a web application.
Web WebApplication `json:"web,omitempty"`
}
-
-type ApplicationList struct {
- Count int `json:"@odata.count,omitempty"` // The total count of all results
- NextLink string `json:"@odata.nextLink,omitempty"` // The URL to use for getting the next set of values.
- Value []Application `json:"value"` // A list of applications.
-}
-
-type ApplicationResult struct {
- Error error
- Ok Application
-}
-
-type AppOwnerResult struct {
- AppId string
- Error error
- Ok json.RawMessage
-}
diff --git a/models/azure/automation_account.go b/models/azure/automation_account.go
index 9e494da..c952a38 100644
--- a/models/azure/automation_account.go
+++ b/models/azure/automation_account.go
@@ -50,14 +50,3 @@ func (s AutomationAccount) ResourceGroupId() string {
return ""
}
}
-
-type AutomationAccountList struct {
- NextLink string `json:"nextLink,omitempty"` // The URL to use for getting the next set of values.
- Value []AutomationAccount `json:"value"` // A list of automation accounts.
-}
-
-type AutomationAccountResult struct {
- SubscriptionId string
- Error error
- Ok AutomationAccount
-}
diff --git a/models/azure/container_registry.go b/models/azure/container_registry.go
index 68d560f..d476d48 100644
--- a/models/azure/container_registry.go
+++ b/models/azure/container_registry.go
@@ -47,14 +47,3 @@ func (s ContainerRegistry) ResourceGroupId() string {
return ""
}
}
-
-type ContainerRegistryList struct {
- NextLink string `json:"nextLink,omitempty"` // The URL to use for getting the next set of values.
- Value []ContainerRegistry `json:"value"` // A list of container registries.
-}
-
-type ContainerRegistryResult struct {
- SubscriptionId string
- Error error
- Ok ContainerRegistry
-}
diff --git a/models/azure/descendant-info.go b/models/azure/descendant-info.go
index 003cf91..7f2d400 100644
--- a/models/azure/descendant-info.go
+++ b/models/azure/descendant-info.go
@@ -60,13 +60,3 @@ type DescendantInfo struct {
// - /subscriptions
Type string `json:"type,omitempty"`
}
-
-type DescendantInfoList struct {
- NextLink string `json:"nextLink,omitempty"` // The URL to use for getting the next set of values.
- Value []DescendantInfo `json:"value"` // A list of management group descendants.
-}
-
-type DescendantInfoResult struct {
- Error error
- Ok DescendantInfo
-}
diff --git a/models/azure/device.go b/models/azure/device.go
index 503f022..64fffe0 100644
--- a/models/azure/device.go
+++ b/models/azure/device.go
@@ -18,8 +18,6 @@
package azure
import (
- "encoding/json"
-
"github.com/bloodhoundad/azurehound/v2/enums"
)
@@ -131,20 +129,3 @@ type Device struct {
// Read-only.
TrustType enums.TrustType `json:"trustType,omitempty"`
}
-
-type DeviceList struct {
- Count int `json:"@odata.count,omitempty"` // The total count of all results
- NextLink string `json:"@odata.nextLink,omitempty"` // The URL to use for getting the next set of values.
- Value []Device `json:"value"` // A list of devices.
-}
-
-type DeviceResult struct {
- Error error
- Ok Device
-}
-
-type DeviceRegisteredOwnerResult struct {
- DeviceId string
- Error error
- Ok json.RawMessage
-}
diff --git a/models/azure/directory_object.go b/models/azure/directory_object.go
index 68e1aa7..149b62e 100644
--- a/models/azure/directory_object.go
+++ b/models/azure/directory_object.go
@@ -17,10 +17,6 @@
package azure
-import (
- "encoding/json"
-)
-
// Represents an Azure Active Directory object. The directoryObject type is the base type for many other directory entity types.
type DirectoryObject struct {
// The unique identifier for the object.
@@ -33,9 +29,3 @@ type DirectoryObject struct {
Type string `json:"@odata.type,omitempty"`
}
-
-type DirectoryObjectList struct {
- Count int `json:"@odata.count,omitempty"` // The total count of all results
- NextLink string `json:"@odata.nextLink,omitempty"` // The URL to use for getting the next set of values.
- Value []json.RawMessage `json:"value"` // A list of various Azure AD directory objects.
-}
diff --git a/models/azure/function_app.go b/models/azure/function_app.go
index 92f394e..ab1fc51 100644
--- a/models/azure/function_app.go
+++ b/models/azure/function_app.go
@@ -49,14 +49,3 @@ func (s FunctionApp) ResourceGroupId() string {
return ""
}
}
-
-type FunctionAppList struct {
- NextLink string `json:"nextLink,omitempty"` // The URL to use for getting the next set of values.
- Value []FunctionApp `json:"value"` // A list of function apps
-}
-
-type FunctionAppResult struct {
- SubscriptionId string
- Error error
- Ok FunctionApp
-}
diff --git a/models/azure/group.go b/models/azure/group.go
index 28fb6d1..de58049 100644
--- a/models/azure/group.go
+++ b/models/azure/group.go
@@ -18,8 +18,6 @@
package azure
import (
- "encoding/json"
-
"github.com/bloodhoundad/azurehound/v2/enums"
)
@@ -281,20 +279,3 @@ type Group struct {
// Nullable.
Visibility enums.GroupVisibility `json:"visibility,omitempty"`
}
-
-type GroupList struct {
- Count int `json:"@odata.count,omitempty"` // The total count of all results
- NextLink string `json:"@odata.nextLink,omitempty"` // The URL to use for getting the next set of values.
- Value []Group `json:"value"` // A list of groups.
-}
-
-type GroupResult struct {
- Error error
- Ok Group
-}
-
-type GroupOwnerResult struct {
- Error error
- GroupId string
- Ok json.RawMessage
-}
diff --git a/models/azure/key_vault.go b/models/azure/key_vault.go
index 841eebe..0588310 100644
--- a/models/azure/key_vault.go
+++ b/models/azure/key_vault.go
@@ -56,14 +56,3 @@ func (s KeyVault) ResourceGroupId() string {
return ""
}
}
-
-type KeyVaultList struct {
- NextLink string `json:"nextLink,omitempty"` // The URL to use for getting the next set of values.
- Value []KeyVault `json:"value"` // A list of key vaults.
-}
-
-type KeyVaultResult struct {
- SubscriptionId string
- Error error
- Ok KeyVault
-}
diff --git a/models/azure/logic_app.go b/models/azure/logic_app.go
index 3dcfa9a..67d8527 100644
--- a/models/azure/logic_app.go
+++ b/models/azure/logic_app.go
@@ -47,14 +47,3 @@ func (s LogicApp) ResourceGroupId() string {
return ""
}
}
-
-type LogicAppList struct {
- NextLink string `json:"nextLink,omitempty"` // The URL to use for getting the next set of values.
- Value []LogicApp `json:"value"` // A list of logic apps.
-}
-
-type LogicAppResult struct {
- SubscriptionId string
- Error error
- Ok LogicApp
-}
diff --git a/models/azure/managed_cluster.go b/models/azure/managed_cluster.go
index 1502bbc..e0aa74c 100644
--- a/models/azure/managed_cluster.go
+++ b/models/azure/managed_cluster.go
@@ -50,14 +50,3 @@ func (s ManagedCluster) ResourceGroupId() string {
return ""
}
}
-
-type ManagedClusterList struct {
- NextLink string `json:"nextLink,omitempty"` // The URL to use for getting the next set of values.
- Value []ManagedCluster `json:"value"` // A list of managed clusters.
-}
-
-type ManagedClusterResult struct {
- SubscriptionId string
- Error error
- Ok ManagedCluster
-}
diff --git a/models/azure/management_group.go b/models/azure/management_group.go
index 91f5231..761c7f5 100644
--- a/models/azure/management_group.go
+++ b/models/azure/management_group.go
@@ -29,13 +29,3 @@ type ManagementGroup struct {
// The type of resource: "Microsoft.Management/managementGroups"
Type string `json:"type,omitempty"`
}
-
-type ManagementGroupList struct {
- NextLink string `json:"nextLink,omitempty"` // The URL to use for getting the next set of values.
- Value []ManagementGroup `json:"value"` // A list of tenants.
-}
-
-type ManagementGroupResult struct {
- Error error
- Ok ManagementGroup
-}
diff --git a/models/azure/member_object.go b/models/azure/member_object.go
deleted file mode 100644
index 40b14e5..0000000
--- a/models/azure/member_object.go
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (C) 2022 Specter Ops, Inc.
-//
-// This file is part of AzureHound.
-//
-// AzureHound is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// AzureHound is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see .
-
-package azure
-
-import "encoding/json"
-
-type MemberObjectList struct {
- Count int `json:"@odata.count,omitempty"` // The total count of all results
- NextLink string `json:"@odata.nextLink,omitempty"` // The URL to use for getting the next set of values.
- Context string `json:"@odata.context,omitempty"`
- Value []json.RawMessage `json:"value"`
-}
-
-type MemberObjectResult struct {
- ParentId string
- ParentType string
- Error error
- Ok json.RawMessage
-}
diff --git a/models/azure/resource_group.go b/models/azure/resource_group.go
index 43604b0..3f73076 100644
--- a/models/azure/resource_group.go
+++ b/models/azure/resource_group.go
@@ -39,14 +39,3 @@ type ResourceGroup struct {
// The type of the resource group.
Type string `json:"type,omitempty"`
}
-
-type ResourceGroupList struct {
- NextLink string `json:"nextLink,omitempty"` // The URL to use for getting the next set of values.
- Value []ResourceGroup `json:"value"` // A list of tenants.
-}
-
-type ResourceGroupResult struct {
- SubscriptionId string
- Error error
- Ok ResourceGroup
-}
diff --git a/models/azure/role.go b/models/azure/role.go
index 5f35dd0..30a25c1 100644
--- a/models/azure/role.go
+++ b/models/azure/role.go
@@ -67,14 +67,3 @@ type Role struct {
// Read-only when isBuiltIn is true
Version string `json:"version,omitempty"`
}
-
-type RoleList struct {
- Count int `json:"@odata.count,omitempty"` // The total count of all results
- NextLink string `json:"@odata.nextLink,omitempty"` // The URL to use for getting the next set of values.
- Value []Role `json:"value"` // A list of roles.
-}
-
-type RoleResult struct {
- Error error
- Ok Role
-}
diff --git a/models/azure/role_assignment.go b/models/azure/role_assignment.go
index 10948c3..07ea735 100644
--- a/models/azure/role_assignment.go
+++ b/models/azure/role_assignment.go
@@ -42,20 +42,6 @@ type RoleAssignment struct {
Properties RoleAssignmentPropertiesWithScope `json:"properties,omitempty"`
}
-type RoleAssignmentList struct {
- // The URL to use for getting the next set of results.
- NextLink string `json:"nextLink,omitempty"`
-
- // The role assignment list.
- Value []RoleAssignment `json:"value"`
-}
-
-type RoleAssignmentResult struct {
- ParentId string
- Error error
- Ok RoleAssignment
-}
-
func (s RoleAssignment) GetPrincipalId() string {
return s.Properties.PrincipalId
}
diff --git a/models/azure/service_principal.go b/models/azure/service_principal.go
index 3a422c0..5ba521b 100644
--- a/models/azure/service_principal.go
+++ b/models/azure/service_principal.go
@@ -18,8 +18,6 @@
package azure
import (
- "encoding/json"
-
"github.com/bloodhoundad/azurehound/v2/enums"
)
@@ -179,20 +177,3 @@ type ServicePrincipal struct {
// Specifies the verified publisher of the application which this service principal represents.
VerifiedPublisher VerifiedPublisher `json:"verifiedPublisher,omitempty"`
}
-
-type ServicePrincipalList struct {
- Count int `json:"@odata.count,omitempty"` // The total count of all results
- NextLink string `json:"@odata.nextLink,omitempty"` // The URL to use for getting the next set of values.
- Value []ServicePrincipal `json:"value"` // A list of ServicePrincipals.
-}
-
-type ServicePrincipalResult struct {
- Error error
- Ok ServicePrincipal
-}
-
-type ServicePrincipalOwnerResult struct {
- Error error
- ServicePrincipalId string
- Ok json.RawMessage
-}
diff --git a/models/azure/storage_account.go b/models/azure/storage_account.go
index 6e2d0ad..a422080 100644
--- a/models/azure/storage_account.go
+++ b/models/azure/storage_account.go
@@ -50,14 +50,3 @@ func (s StorageAccount) ResourceGroupId() string {
return ""
}
}
-
-type StorageAccountList struct {
- NextLink string `json:"nextLink,omitempty"` // The URL to use for getting the next set of values.
- Value []StorageAccount `json:"value"` // A list of storage accounts.
-}
-
-type StorageAccountResult struct {
- SubscriptionId string
- Error error
- Ok StorageAccount
-}
diff --git a/models/azure/storage_container.go b/models/azure/storage_container.go
index 7e841cf..5a22612 100644
--- a/models/azure/storage_container.go
+++ b/models/azure/storage_container.go
@@ -63,14 +63,3 @@ func (s StorageContainer) StorageAccountId() string {
return ""
}
}
-
-type StorageContainerList struct {
- NextLink string `json:"nextLink,omitempty"` // The URL to use for getting the next set of values.
- Value []StorageContainer `json:"value"` // A list of storage containers.
-}
-
-type StorageContainerResult struct {
- SubscriptionId string
- Error error
- Ok StorageContainer
-}
diff --git a/models/azure/subscription.go b/models/azure/subscription.go
index 30a710c..b7f32c0 100644
--- a/models/azure/subscription.go
+++ b/models/azure/subscription.go
@@ -49,13 +49,3 @@ type Subscription struct {
// The subscription tenant ID.
TenantId string `json:"tenantId,omitempty"`
}
-
-type SubscriptionList struct {
- NextLink string `json:"nextLink,omitempty"` // The URL to use for getting the next set of values.
- Value []Subscription `json:"value"` // A list of subscriptions.
-}
-
-type SubscriptionResult struct {
- Error error
- Ok Subscription
-}
diff --git a/models/azure/tenant.go b/models/azure/tenant.go
index e0d5030..727e0c5 100644
--- a/models/azure/tenant.go
+++ b/models/azure/tenant.go
@@ -36,8 +36,3 @@ type TenantList struct {
NextLink string `json:"nextLink,omitempty"` // The URL to use for getting the next set of values.
Value []Tenant `json:"value"` // A list of tenants.
}
-
-type TenantResult struct {
- Error error
- Ok Tenant
-}
diff --git a/models/azure/unified_role_assignment.go b/models/azure/unified_role_assignment.go
index 6027e59..fc60a5f 100644
--- a/models/azure/unified_role_assignment.go
+++ b/models/azure/unified_role_assignment.go
@@ -74,14 +74,3 @@ type UnifiedRoleAssignment struct {
// Supports $expand.
AppScope AppScope `json:"appScope,omitempty"`
}
-
-type UnifiedRoleAssignmentList struct {
- Count int `json:"@odata.count,omitempty"` // The total count of all results
- NextLink string `json:"@odata.nextLink,omitempty"` // The URL to use for getting the next set of values.
- Value []UnifiedRoleAssignment `json:"value"` // A list of role assignments.
-}
-
-type UnifiedRoleAssignmentResult struct {
- Error error
- Ok UnifiedRoleAssignment
-}
diff --git a/models/azure/user.go b/models/azure/user.go
index 8106d12..301b5d7 100644
--- a/models/azure/user.go
+++ b/models/azure/user.go
@@ -465,14 +465,3 @@ type User struct {
// Supports $filter (eq, ne, NOT, in).
UserType string `json:"userType,omitempty"`
}
-
-type UserList struct {
- Count int `json:"@odata.count,omitempty"` // The total count of all results
- NextLink string `json:"@odata.nextLink,omitempty"` // The URL to use for getting the next set of values.
- Value []User `json:"value"` // A list of users.
-}
-
-type UserResult struct {
- Error error
- Ok User
-}
diff --git a/models/azure/virtual_machine.go b/models/azure/virtual_machine.go
index 4c996b7..64cbb48 100644
--- a/models/azure/virtual_machine.go
+++ b/models/azure/virtual_machine.go
@@ -51,14 +51,3 @@ func (s VirtualMachine) ResourceGroupId() string {
return ""
}
}
-
-type VirtualMachineList struct {
- NextLink string `json:"nextLink,omitempty"` // The URL to use for getting the next set of values.
- Value []VirtualMachine `json:"value"` // A list of virtual machines.
-}
-
-type VirtualMachineResult struct {
- SubscriptionId string
- Error error
- Ok VirtualMachine
-}
diff --git a/models/azure/vm_scale_set.go b/models/azure/vm_scale_set.go
index 59b8edd..3d89b1f 100644
--- a/models/azure/vm_scale_set.go
+++ b/models/azure/vm_scale_set.go
@@ -49,14 +49,3 @@ func (s VMScaleSet) ResourceGroupId() string {
return ""
}
}
-
-type VMScaleSetList struct {
- NextLink string `json:"nextLink,omitempty"` // The URL to use for getting the next set of values.
- Value []VMScaleSet `json:"value"` // A list of virtual machine scale sets.
-}
-
-type VMScaleSetResult struct {
- SubscriptionId string
- Error error
- Ok VMScaleSet
-}
diff --git a/models/azure/web_app.go b/models/azure/web_app.go
index 128bc85..9ef401d 100644
--- a/models/azure/web_app.go
+++ b/models/azure/web_app.go
@@ -48,14 +48,3 @@ func (s WebApp) ResourceGroupId() string {
return ""
}
}
-
-type WebAppList struct {
- NextLink string `json:"nextLink,omitempty"` // The URL to use for getting the next set of values.
- Value []WebApp `json:"value"` // A list of web apps.
-}
-
-type WebAppResult struct {
- SubscriptionId string
- Error error
- Ok WebApp
-}