diff --git a/client/app_role_assignments.go b/client/app_role_assignments.go index fbcba83..c2eac7a 100644 --- a/client/app_role_assignments.go +++ b/client/app_role_assignments.go @@ -27,6 +27,7 @@ import ( "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/pipeline" ) func (s *azureClient) GetAzureADAppRoleAssignments(ctx context.Context, servicePrincipalId string, filter, search, orderBy, expand string, selectCols []string, top int32, count bool) (azure.AppRoleAssignmentList, error) { @@ -64,10 +65,14 @@ func (s *azureClient) ListAzureADAppRoleAssignments(ctx context.Context, service if list, err := s.GetAzureADAppRoleAssignments(ctx, servicePrincipal, filter, search, orderBy, expand, selectCols, 999, false); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range list.Value { - out <- azure.AppRoleAssignmentResult{Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.AppRoleAssignmentResult{Ok: u}); !ok { + return + } } nextLink = list.NextLink @@ -75,23 +80,33 @@ func (s *azureClient) ListAzureADAppRoleAssignments(ctx context.Context, service var list azure.AppRoleAssignmentList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if res, err := s.msgraph.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if err := rest.Decode(res.Body, &list); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else { for _, u := range list.Value { - out <- azure.AppRoleAssignmentResult{Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.AppRoleAssignmentResult{Ok: u}); !ok { + return + } } nextLink = list.NextLink } diff --git a/client/apps.go b/client/apps.go index b509b6e..1091a31 100644 --- a/client/apps.go +++ b/client/apps.go @@ -28,6 +28,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/constants" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models/azure" + "github.com/bloodhoundad/azurehound/v2/pipeline" ) func (s *azureClient) GetAzureADApp(ctx context.Context, objectId string, selectCols []string) (*azure.Application, error) { @@ -113,10 +114,14 @@ func (s *azureClient) ListAzureADApps(ctx context.Context, filter, search, order if list, err := s.GetAzureADApps(ctx, filter, search, orderBy, expand, selectCols, 999, false); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range list.Value { - out <- azure.ApplicationResult{Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.ApplicationResult{Ok: u}); !ok { + return + } } nextLink = list.NextLink @@ -124,23 +129,33 @@ func (s *azureClient) ListAzureADApps(ctx context.Context, filter, search, order var list azure.ApplicationList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } return } else if res, err := s.msgraph.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } return } else if err := rest.Decode(res.Body, &list); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } return } else { for _, u := range list.Value { - out <- azure.ApplicationResult{Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.ApplicationResult{Ok: u}); !ok { + return + } } nextLink = list.NextLink } @@ -163,12 +178,16 @@ func (s *azureClient) ListAzureADAppOwners(ctx context.Context, objectId string, if list, err := s.GetAzureADAppOwners(ctx, objectId, filter, search, orderBy, selectCols, 999, false); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range list.Value { - out <- azure.AppOwnerResult{ + if ok := pipeline.Send(ctx.Done(), out, azure.AppOwnerResult{ AppId: objectId, Ok: u, + }); !ok { + return } } @@ -177,25 +196,35 @@ func (s *azureClient) ListAzureADAppOwners(ctx context.Context, objectId string, var list azure.DirectoryObjectList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } return } else if res, err := s.msgraph.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } return } else if err := rest.Decode(res.Body, &list); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } return } else { for _, u := range list.Value { - out <- azure.AppOwnerResult{ + if ok := pipeline.Send(ctx.Done(), out, azure.AppOwnerResult{ AppId: objectId, Ok: u, + }); !ok { + return } } nextLink = list.NextLink @@ -221,13 +250,17 @@ func (s *azureClient) ListAzureADAppMemberObjects(ctx context.Context, objectId ) if list, err := s.GetAzureADAppMemberObjects(ctx, objectId, securityEnabledOnly); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range list.Value { - out <- azure.MemberObjectResult{ + if ok := pipeline.Send(ctx.Done(), out, azure.MemberObjectResult{ ParentId: objectId, ParentType: string(enums.EntityApplication), Ok: u, + }); !ok { + return } } @@ -236,26 +269,36 @@ func (s *azureClient) ListAzureADAppMemberObjects(ctx context.Context, objectId var list azure.MemberObjectList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if res, err := s.msgraph.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if err := rest.Decode(res.Body, &list); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else { for _, u := range list.Value { - out <- azure.MemberObjectResult{ + if ok := pipeline.Send(ctx.Done(), out, azure.MemberObjectResult{ ParentId: objectId, ParentType: string(enums.EntityApplication), Ok: u, + }); !ok { + return } } nextLink = list.NextLink diff --git a/client/automation_accounts.go b/client/automation_accounts.go index 53cd564..2131acf 100644 --- a/client/automation_accounts.go +++ b/client/automation_accounts.go @@ -25,6 +25,7 @@ import ( "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/pipeline" ) func (s *azureClient) GetAzureAutomationAccount(ctx context.Context, subscriptionId, groupName, aaName, expand string) (*azure.AutomationAccount, error) { @@ -75,10 +76,14 @@ func (s *azureClient) ListAzureAutomationAccounts(ctx context.Context, subscript if result, err := s.GetAzureAutomationAccounts(ctx, subscriptionId); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range result.Value { - out <- azure.AutomationAccountResult{SubscriptionId: subscriptionId, Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.AutomationAccountResult{SubscriptionId: subscriptionId, Ok: u}); !ok { + return + } } nextLink = result.NextLink @@ -86,25 +91,35 @@ func (s *azureClient) ListAzureAutomationAccounts(ctx context.Context, subscript var list azure.AutomationAccountList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if res, err := s.resourceManager.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if err := rest.Decode(res.Body, &list); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else { for _, u := range list.Value { - out <- azure.AutomationAccountResult{ + if ok := pipeline.Send(ctx.Done(), out, azure.AutomationAccountResult{ SubscriptionId: "/subscriptions/" + subscriptionId, Ok: u, + }); !ok { + return } } nextLink = list.NextLink diff --git a/client/container_registries.go b/client/container_registries.go index 77e10f6..8aeecdc 100644 --- a/client/container_registries.go +++ b/client/container_registries.go @@ -25,6 +25,7 @@ import ( "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/pipeline" ) func (s *azureClient) GetAzureContainerRegistry(ctx context.Context, subscriptionId, groupName, crName, expand string) (*azure.ContainerRegistry, error) { @@ -75,10 +76,14 @@ func (s *azureClient) ListAzureContainerRegistries(ctx context.Context, subscrip if result, err := s.GetAzureContainerRegistries(ctx, subscriptionId); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range result.Value { - out <- azure.ContainerRegistryResult{SubscriptionId: subscriptionId, Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.ContainerRegistryResult{SubscriptionId: subscriptionId, Ok: u}); !ok { + return + } } nextLink = result.NextLink @@ -86,25 +91,35 @@ func (s *azureClient) ListAzureContainerRegistries(ctx context.Context, subscrip var list azure.ContainerRegistryList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if res, err := s.resourceManager.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if err := rest.Decode(res.Body, &list); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else { for _, u := range list.Value { - out <- azure.ContainerRegistryResult{ + if ok := pipeline.Send(ctx.Done(), out, azure.ContainerRegistryResult{ SubscriptionId: "/subscriptions/" + subscriptionId, Ok: u, + }); !ok { + return } } nextLink = list.NextLink diff --git a/client/devices.go b/client/devices.go index 6aa3849..8b811a2 100644 --- a/client/devices.go +++ b/client/devices.go @@ -27,6 +27,7 @@ import ( "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/pipeline" ) func (s *azureClient) GetAzureDevice(ctx context.Context, objectId string, selectCols []string) (*azure.Device, error) { @@ -94,10 +95,14 @@ func (s *azureClient) ListAzureDevices(ctx context.Context, filter, search, orde if list, err := s.GetAzureDevices(ctx, filter, search, orderBy, expand, selectCols, 999, false); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range list.Value { - out <- azure.DeviceResult{Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.DeviceResult{Ok: u}); !ok { + return + } } nextLink = list.NextLink @@ -105,23 +110,33 @@ func (s *azureClient) ListAzureDevices(ctx context.Context, filter, search, orde var list azure.DeviceList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if res, err := s.msgraph.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if err := rest.Decode(res.Body, &list); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else { for _, u := range list.Value { - out <- azure.DeviceResult{Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.DeviceResult{Ok: u}); !ok { + return + } } nextLink = list.NextLink } @@ -146,12 +161,16 @@ func (s *azureClient) ListAzureDeviceRegisteredOwners(ctx context.Context, objec if list, err := s.GetAzureDeviceRegisteredOwners(ctx, objectId, "", "", false); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range list.Value { - out <- azure.DeviceRegisteredOwnerResult{ + if ok := pipeline.Send(ctx.Done(), out, azure.DeviceRegisteredOwnerResult{ DeviceId: objectId, Ok: u, + }); !ok { + return } } @@ -160,25 +179,35 @@ func (s *azureClient) ListAzureDeviceRegisteredOwners(ctx context.Context, objec var list azure.DirectoryObjectList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if res, err := s.msgraph.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if err := rest.Decode(res.Body, &list); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else { for _, u := range list.Value { - out <- azure.DeviceRegisteredOwnerResult{ + if ok := pipeline.Send(ctx.Done(), out, azure.DeviceRegisteredOwnerResult{ DeviceId: objectId, Ok: u, + }); !ok { + return } } nextLink = list.NextLink diff --git a/client/function_apps.go b/client/function_apps.go index a572315..640acce 100644 --- a/client/function_apps.go +++ b/client/function_apps.go @@ -25,6 +25,7 @@ import ( "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/pipeline" ) func (s *azureClient) GetAzureFunctionApp(ctx context.Context, subscriptionId, groupName, functionAppName, expand string) (*azure.FunctionApp, error) { @@ -75,10 +76,14 @@ func (s *azureClient) ListAzureFunctionApps(ctx context.Context, subscriptionId if result, err := s.GetAzureFunctionApps(ctx, subscriptionId); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range result.Value { - out <- azure.FunctionAppResult{SubscriptionId: subscriptionId, Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.FunctionAppResult{SubscriptionId: subscriptionId, Ok: u}); !ok { + return + } } nextLink = result.NextLink @@ -86,25 +91,35 @@ func (s *azureClient) ListAzureFunctionApps(ctx context.Context, subscriptionId var list azure.FunctionAppList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if res, err := s.resourceManager.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if err := rest.Decode(res.Body, &list); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else { for _, u := range list.Value { - out <- azure.FunctionAppResult{ + if ok := pipeline.Send(ctx.Done(), out, azure.FunctionAppResult{ SubscriptionId: "/subscriptions/" + subscriptionId, Ok: u, + }); !ok { + return } } nextLink = list.NextLink diff --git a/client/groups.go b/client/groups.go index 7cd7dfa..4e205f8 100644 --- a/client/groups.go +++ b/client/groups.go @@ -28,6 +28,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/constants" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models/azure" + "github.com/bloodhoundad/azurehound/v2/pipeline" ) func (s *azureClient) GetAzureADGroup(ctx context.Context, objectId string, selectCols []string) (*azure.Group, error) { @@ -110,10 +111,14 @@ func (s *azureClient) ListAzureADGroups(ctx context.Context, filter, search, ord if list, err := s.GetAzureADGroups(ctx, filter, search, orderBy, expand, selectCols, 999, false); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range list.Value { - out <- azure.GroupResult{Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.GroupResult{Ok: u}); !ok { + return + } } nextLink = list.NextLink @@ -121,23 +126,33 @@ func (s *azureClient) ListAzureADGroups(ctx context.Context, filter, search, ord var list azure.GroupList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if res, err := s.msgraph.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if err := rest.Decode(res.Body, &list); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else { for _, u := range list.Value { - out <- azure.GroupResult{Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.GroupResult{Ok: u}); !ok { + return + } } nextLink = list.NextLink } @@ -160,12 +175,16 @@ func (s *azureClient) ListAzureADGroupOwners(ctx context.Context, objectId strin if list, err := s.GetAzureADGroupOwners(ctx, objectId, filter, search, orderBy, selectCols, 999, false); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range list.Value { - out <- azure.GroupOwnerResult{ + if ok := pipeline.Send(ctx.Done(), out, azure.GroupOwnerResult{ GroupId: objectId, Ok: u, + }); !ok { + return } } @@ -174,25 +193,35 @@ func (s *azureClient) ListAzureADGroupOwners(ctx context.Context, objectId strin var list azure.DirectoryObjectList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if res, err := s.msgraph.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if err := rest.Decode(res.Body, &list); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else { for _, u := range list.Value { - out <- azure.GroupOwnerResult{ + if ok := pipeline.Send(ctx.Done(), out, azure.GroupOwnerResult{ GroupId: objectId, Ok: u, + }); !ok { + return } } nextLink = list.NextLink @@ -219,13 +248,17 @@ func (s *azureClient) ListAzureADGroupMembers(ctx context.Context, objectId stri if list, err := s.GetAzureADGroupMembers(ctx, objectId, filter, search, false); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range list.Value { - out <- azure.MemberObjectResult{ + if ok := pipeline.Send(ctx.Done(), out, azure.MemberObjectResult{ ParentId: objectId, ParentType: string(enums.EntityGroup), Ok: u, + }); !ok { + return } } @@ -234,26 +267,36 @@ func (s *azureClient) ListAzureADGroupMembers(ctx context.Context, objectId stri var list azure.MemberObjectList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if res, err := s.msgraph.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if err := rest.Decode(res.Body, &list); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else { for _, u := range list.Value { - out <- azure.MemberObjectResult{ + if ok := pipeline.Send(ctx.Done(), out, azure.MemberObjectResult{ ParentId: objectId, ParentType: string(enums.EntityGroup), Ok: u, + }); !ok { + return } } nextLink = list.NextLink diff --git a/client/keyvaults.go b/client/keyvaults.go index 8fe1993..991cd6c 100644 --- a/client/keyvaults.go +++ b/client/keyvaults.go @@ -25,6 +25,7 @@ import ( "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/pipeline" ) func (s *azureClient) GetAzureKeyVault(ctx context.Context, subscriptionId, groupName, vaultName string) (*azure.KeyVault, error) { @@ -75,12 +76,16 @@ func (s *azureClient) ListAzureKeyVaults(ctx context.Context, subscriptionId str if result, err := s.GetAzureKeyVaults(ctx, subscriptionId, top); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range result.Value { - out <- azure.KeyVaultResult{ + if ok := pipeline.Send(ctx.Done(), out, azure.KeyVaultResult{ SubscriptionId: subscriptionId, Ok: u, + }); !ok { + return } } @@ -89,25 +94,35 @@ func (s *azureClient) ListAzureKeyVaults(ctx context.Context, subscriptionId str var list azure.KeyVaultList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if res, err := s.resourceManager.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if err := rest.Decode(res.Body, &list); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else { for _, u := range list.Value { - out <- azure.KeyVaultResult{ + if ok := pipeline.Send(ctx.Done(), out, azure.KeyVaultResult{ SubscriptionId: subscriptionId, Ok: u, + }); !ok { + return } } nextLink = list.NextLink diff --git a/client/logic_apps.go b/client/logic_apps.go index 68fa9dd..70d1257 100644 --- a/client/logic_apps.go +++ b/client/logic_apps.go @@ -25,6 +25,7 @@ import ( "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/pipeline" ) func (s *azureClient) GetAzureLogicApp(ctx context.Context, subscriptionId, groupName, logicappName, expand string) (*azure.LogicApp, error) { @@ -75,10 +76,14 @@ func (s *azureClient) ListAzureLogicApps(ctx context.Context, subscriptionId str if result, err := s.GetAzureLogicApps(ctx, subscriptionId, filter, top); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range result.Value { - out <- azure.LogicAppResult{SubscriptionId: subscriptionId, Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.LogicAppResult{SubscriptionId: subscriptionId, Ok: u}); !ok { + return + } } nextLink = result.NextLink @@ -86,25 +91,35 @@ func (s *azureClient) ListAzureLogicApps(ctx context.Context, subscriptionId str var list azure.LogicAppList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if res, err := s.resourceManager.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if err := rest.Decode(res.Body, &list); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else { for _, u := range list.Value { - out <- azure.LogicAppResult{ + if ok := pipeline.Send(ctx.Done(), out, azure.LogicAppResult{ SubscriptionId: "/subscriptions/" + subscriptionId, Ok: u, + }); !ok { + return } } nextLink = list.NextLink diff --git a/client/managed_clusters.go b/client/managed_clusters.go index 2deeac8..13168ac 100644 --- a/client/managed_clusters.go +++ b/client/managed_clusters.go @@ -25,6 +25,7 @@ import ( "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/pipeline" ) func (s *azureClient) GetAzureManagedCluster(ctx context.Context, subscriptionId, groupName, mcName, expand string) (*azure.ManagedCluster, error) { @@ -75,10 +76,14 @@ func (s *azureClient) ListAzureManagedClusters(ctx context.Context, subscription if result, err := s.GetAzureManagedClusters(ctx, subscriptionId, statusOnly); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range result.Value { - out <- azure.ManagedClusterResult{SubscriptionId: subscriptionId, Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.ManagedClusterResult{SubscriptionId: subscriptionId, Ok: u}); !ok { + return + } } nextLink = result.NextLink @@ -86,25 +91,35 @@ func (s *azureClient) ListAzureManagedClusters(ctx context.Context, subscription var list azure.ManagedClusterList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if res, err := s.resourceManager.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if err := rest.Decode(res.Body, &list); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else { for _, u := range list.Value { - out <- azure.ManagedClusterResult{ + if ok := pipeline.Send(ctx.Done(), out, azure.ManagedClusterResult{ SubscriptionId: "/subscriptions/" + subscriptionId, Ok: u, + }); !ok { + return } } nextLink = list.NextLink diff --git a/client/management_groups.go b/client/management_groups.go index 53ab49f..673c9b0 100644 --- a/client/management_groups.go +++ b/client/management_groups.go @@ -25,6 +25,7 @@ import ( "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/pipeline" ) func (s *azureClient) GetAzureManagementGroup(ctx context.Context, groupId, filter, expand string, recurse bool) (*azure.ManagementGroup, error) { @@ -90,10 +91,14 @@ func (s *azureClient) ListAzureManagementGroups(ctx context.Context) <-chan azur if result, err := s.GetAzureManagementGroups(ctx); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range result.Value { - out <- azure.ManagementGroupResult{Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.ManagementGroupResult{Ok: u}); !ok { + return + } } nextLink = result.NextLink @@ -101,23 +106,33 @@ func (s *azureClient) ListAzureManagementGroups(ctx context.Context) <-chan azur var list azure.ManagementGroupList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if res, err := s.resourceManager.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if err := rest.Decode(res.Body, &list); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else { for _, u := range list.Value { - out <- azure.ManagementGroupResult{Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.ManagementGroupResult{Ok: u}); !ok { + return + } } nextLink = list.NextLink } @@ -140,10 +155,14 @@ func (s *azureClient) ListAzureManagementGroupDescendants(ctx context.Context, g if result, err := s.GetAzureManagementGroupDescendants(ctx, groupId, 3000); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range result.Value { - out <- azure.DescendantInfoResult{Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.DescendantInfoResult{Ok: u}); !ok { + return + } } nextLink = result.NextLink @@ -151,23 +170,33 @@ func (s *azureClient) ListAzureManagementGroupDescendants(ctx context.Context, g var list azure.DescendantInfoList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if res, err := s.resourceManager.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if err := rest.Decode(res.Body, &list); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else { for _, u := range list.Value { - out <- azure.DescendantInfoResult{Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.DescendantInfoResult{Ok: u}); !ok { + return + } } nextLink = list.NextLink } diff --git a/client/resource_groups.go b/client/resource_groups.go index 9c37679..3164c0f 100644 --- a/client/resource_groups.go +++ b/client/resource_groups.go @@ -25,6 +25,7 @@ import ( "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/pipeline" ) func (s *azureClient) GetAzureResourceGroup(ctx context.Context, subscriptionId, groupName string) (*azure.ResourceGroup, error) { @@ -74,12 +75,16 @@ func (s *azureClient) ListAzureResourceGroups(ctx context.Context, subscriptionI if result, err := s.GetAzureResourceGroups(ctx, subscriptionId, filter, 1000); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range result.Value { - out <- azure.ResourceGroupResult{ + if ok := pipeline.Send(ctx.Done(), out, azure.ResourceGroupResult{ SubscriptionId: objectId, Ok: u, + }); !ok { + return } } @@ -88,25 +93,35 @@ func (s *azureClient) ListAzureResourceGroups(ctx context.Context, subscriptionI var list azure.ResourceGroupList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if res, err := s.resourceManager.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if err := rest.Decode(res.Body, &list); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else { for _, u := range list.Value { - out <- azure.ResourceGroupResult{ + if ok := pipeline.Send(ctx.Done(), out, azure.ResourceGroupResult{ SubscriptionId: objectId, Ok: u, + }); !ok { + return } } nextLink = list.NextLink diff --git a/client/role_assignments.go b/client/role_assignments.go index 2304fbb..fd94cd4 100644 --- a/client/role_assignments.go +++ b/client/role_assignments.go @@ -27,6 +27,7 @@ import ( "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/pipeline" ) func (s *azureClient) GetAzureADRoleAssignment(ctx context.Context, objectId string, selectCols []string) (*azure.UnifiedRoleAssignment, error) { @@ -79,10 +80,14 @@ func (s *azureClient) ListAzureADRoleAssignments(ctx context.Context, filter, se if list, err := s.GetAzureADRoleAssignments(ctx, filter, search, orderBy, expand, selectCols, 999, false); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range list.Value { - out <- azure.UnifiedRoleAssignmentResult{Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.UnifiedRoleAssignmentResult{Ok: u}); !ok { + return + } } nextLink = list.NextLink @@ -90,23 +95,33 @@ func (s *azureClient) ListAzureADRoleAssignments(ctx context.Context, filter, se var list azure.UnifiedRoleAssignmentList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if res, err := s.msgraph.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if err := rest.Decode(res.Body, &list); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else { for _, u := range list.Value { - out <- azure.UnifiedRoleAssignmentResult{Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.UnifiedRoleAssignmentResult{Ok: u}); !ok { + return + } } nextLink = list.NextLink } @@ -147,12 +162,16 @@ func (s *azureClient) ListRoleAssignmentsForResource(ctx context.Context, resour if result, err := s.GetRoleAssignmentsForResource(ctx, resourceId, filter); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range result.Value { - out <- azure.RoleAssignmentResult{ + if ok := pipeline.Send(ctx.Done(), out, azure.RoleAssignmentResult{ ParentId: resourceId, Ok: u, + }); !ok { + return } } @@ -161,25 +180,35 @@ func (s *azureClient) ListRoleAssignmentsForResource(ctx context.Context, resour var list azure.RoleAssignmentList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if res, err := s.resourceManager.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if err := rest.Decode(res.Body, &list); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else { for _, u := range list.Value { - out <- azure.RoleAssignmentResult{ + if ok := pipeline.Send(ctx.Done(), out, azure.RoleAssignmentResult{ ParentId: resourceId, Ok: u, + }); !ok { + return } } nextLink = list.NextLink @@ -220,12 +249,16 @@ func (s *azureClient) ListResourceRoleAssignments(ctx context.Context, subscript if result, err := s.GetResourceRoleAssignments(ctx, subscriptionId, filter, expand); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range result.Value { - out <- azure.RoleAssignmentResult{ + if ok := pipeline.Send(ctx.Done(), out, azure.RoleAssignmentResult{ ParentId: subscriptionId, Ok: u, + }); !ok { + return } } @@ -234,25 +267,35 @@ func (s *azureClient) ListResourceRoleAssignments(ctx context.Context, subscript var list azure.RoleAssignmentList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if res, err := s.resourceManager.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if err := rest.Decode(res.Body, &list); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else { for _, u := range list.Value { - out <- azure.RoleAssignmentResult{ + if ok := pipeline.Send(ctx.Done(), out, azure.RoleAssignmentResult{ ParentId: subscriptionId, Ok: u, + }); !ok { + return } } nextLink = list.NextLink diff --git a/client/roles.go b/client/roles.go index c28031c..006c003 100644 --- a/client/roles.go +++ b/client/roles.go @@ -26,6 +26,7 @@ import ( "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/pipeline" ) func (s *azureClient) GetAzureADRole(ctx context.Context, roleId string, selectCols []string) (*azure.Role, error) { @@ -73,10 +74,14 @@ func (s *azureClient) ListAzureADRoles(ctx context.Context, filter, expand strin if users, err := s.GetAzureADRoles(ctx, filter, expand); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range users.Value { - out <- azure.RoleResult{Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.RoleResult{Ok: u}); !ok { + return + } } nextLink = users.NextLink @@ -84,23 +89,33 @@ func (s *azureClient) ListAzureADRoles(ctx context.Context, filter, expand strin var users azure.RoleList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if res, err := s.msgraph.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if err := rest.Decode(res.Body, &users); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else { for _, u := range users.Value { - out <- azure.RoleResult{Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.RoleResult{Ok: u}); !ok { + return + } } nextLink = users.NextLink } diff --git a/client/service_principals.go b/client/service_principals.go index fa8e422..9c1d39b 100644 --- a/client/service_principals.go +++ b/client/service_principals.go @@ -27,6 +27,7 @@ import ( "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/pipeline" ) func (s *azureClient) GetAzureADServicePrincipal(ctx context.Context, objectId string, selectCols []string) (*azure.ServicePrincipal, error) { @@ -94,10 +95,14 @@ func (s *azureClient) ListAzureADServicePrincipals(ctx context.Context, filter, if list, err := s.GetAzureADServicePrincipals(ctx, filter, search, orderBy, expand, selectCols, 999, false); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range list.Value { - out <- azure.ServicePrincipalResult{Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.ServicePrincipalResult{Ok: u}); !ok { + return + } } nextLink = list.NextLink @@ -105,23 +110,33 @@ func (s *azureClient) ListAzureADServicePrincipals(ctx context.Context, filter, var list azure.ServicePrincipalList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if res, err := s.msgraph.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if err := rest.Decode(res.Body, &list); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else { for _, u := range list.Value { - out <- azure.ServicePrincipalResult{Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.ServicePrincipalResult{Ok: u}); !ok { + return + } } nextLink = list.NextLink } @@ -146,12 +161,16 @@ func (s *azureClient) ListAzureADServicePrincipalOwners(ctx context.Context, obj if list, err := s.GetAzureADServicePrincipalOwners(ctx, objectId, filter, search, orderBy, selectCols, 999, false); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range list.Value { - out <- azure.ServicePrincipalOwnerResult{ + if ok := pipeline.Send(ctx.Done(), out, azure.ServicePrincipalOwnerResult{ ServicePrincipalId: objectId, Ok: u, + }); !ok { + return } } @@ -160,25 +179,35 @@ func (s *azureClient) ListAzureADServicePrincipalOwners(ctx context.Context, obj var list azure.DirectoryObjectList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if res, err := s.msgraph.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if err := rest.Decode(res.Body, &list); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else { for _, u := range list.Value { - out <- azure.ServicePrincipalOwnerResult{ + if ok := pipeline.Send(ctx.Done(), out, azure.ServicePrincipalOwnerResult{ ServicePrincipalId: objectId, Ok: u, + }); !ok { + return } } nextLink = list.NextLink diff --git a/client/storage_accounts.go b/client/storage_accounts.go index 5379f09..50f40c9 100644 --- a/client/storage_accounts.go +++ b/client/storage_accounts.go @@ -25,6 +25,7 @@ import ( "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/pipeline" ) func (s *azureClient) GetAzureStorageAccount(ctx context.Context, subscriptionId, groupName, saName, expand string) (*azure.StorageAccount, error) { @@ -74,10 +75,14 @@ func (s *azureClient) ListAzureStorageAccounts(ctx context.Context, subscription if result, err := s.GetAzureStorageAccounts(ctx, subscriptionId); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range result.Value { - out <- azure.StorageAccountResult{SubscriptionId: subscriptionId, Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.StorageAccountResult{SubscriptionId: subscriptionId, Ok: u}); !ok { + return + } } nextLink = result.NextLink @@ -85,25 +90,35 @@ func (s *azureClient) ListAzureStorageAccounts(ctx context.Context, subscription var list azure.StorageAccountList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if res, err := s.resourceManager.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if err := rest.Decode(res.Body, &list); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else { for _, u := range list.Value { - out <- azure.StorageAccountResult{ + if ok := pipeline.Send(ctx.Done(), out, azure.StorageAccountResult{ SubscriptionId: "/subscriptions/" + subscriptionId, Ok: u, + }); !ok { + return } } nextLink = list.NextLink @@ -165,10 +180,14 @@ func (s *azureClient) ListAzureStorageContainers(ctx context.Context, subscripti if result, err := s.GetAzureStorageContainers(ctx, subscriptionId, resourceGroupName, saName, filter, includeDeleted, maxPageSize); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range result.Value { - out <- azure.StorageContainerResult{SubscriptionId: subscriptionId, Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.StorageContainerResult{SubscriptionId: subscriptionId, Ok: u}); !ok { + return + } } nextLink = result.NextLink @@ -176,25 +195,35 @@ func (s *azureClient) ListAzureStorageContainers(ctx context.Context, subscripti var list azure.StorageContainerList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if res, err := s.resourceManager.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if err := rest.Decode(res.Body, &list); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else { for _, u := range list.Value { - out <- azure.StorageContainerResult{ + if ok := pipeline.Send(ctx.Done(), out, azure.StorageContainerResult{ SubscriptionId: "/subscriptions/" + subscriptionId, Ok: u, + }); !ok { + return } } nextLink = list.NextLink diff --git a/client/subscriptions.go b/client/subscriptions.go index 4b6a9ab..c44c17f 100644 --- a/client/subscriptions.go +++ b/client/subscriptions.go @@ -25,6 +25,7 @@ import ( "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/pipeline" ) func (s *azureClient) GetAzureSubscription(ctx context.Context, objectId string) (*azure.Subscription, error) { @@ -73,10 +74,14 @@ func (s *azureClient) ListAzureSubscriptions(ctx context.Context) <-chan azure.S if result, err := s.GetAzureSubscriptions(ctx); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range result.Value { - out <- azure.SubscriptionResult{Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.SubscriptionResult{Ok: u}); !ok { + return + } } nextLink = result.NextLink @@ -84,23 +89,33 @@ func (s *azureClient) ListAzureSubscriptions(ctx context.Context) <-chan azure.S var list azure.SubscriptionList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if res, err := s.resourceManager.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if err := rest.Decode(res.Body, &list); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else { for _, u := range list.Value { - out <- azure.SubscriptionResult{Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.SubscriptionResult{Ok: u}); !ok { + return + } } nextLink = list.NextLink } diff --git a/client/tenants.go b/client/tenants.go index f9b2439..bd3314e 100644 --- a/client/tenants.go +++ b/client/tenants.go @@ -26,6 +26,7 @@ import ( "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/pipeline" ) func (s *azureClient) GetAzureADOrganization(ctx context.Context, selectCols []string) (*azure.Organization, error) { @@ -73,10 +74,14 @@ func (s *azureClient) ListAzureADTenants(ctx context.Context, includeAllTenantCa if result, err := s.GetAzureADTenants(ctx, includeAllTenantCategories); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range result.Value { - out <- azure.TenantResult{Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.TenantResult{Ok: u}); !ok { + return + } } nextLink = result.NextLink @@ -84,23 +89,33 @@ func (s *azureClient) ListAzureADTenants(ctx context.Context, includeAllTenantCa var list azure.TenantList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if res, err := s.resourceManager.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if err := rest.Decode(res.Body, &list); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else { for _, u := range list.Value { - out <- azure.TenantResult{Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.TenantResult{Ok: u}); !ok { + return + } } nextLink = list.NextLink } diff --git a/client/users.go b/client/users.go index a84713a..98cec6c 100644 --- a/client/users.go +++ b/client/users.go @@ -27,6 +27,7 @@ import ( "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/pipeline" ) func (s *azureClient) GetAzureADUser(ctx context.Context, objectId string, selectCols []string) (*azure.User, error) { @@ -78,10 +79,14 @@ func (s *azureClient) ListAzureADUsers(ctx context.Context, filter string, searc ) if users, err := s.GetAzureADUsers(ctx, filter, search, orderBy, selectCols, 999, false); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range users.Value { - out <- azure.UserResult{Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.UserResult{Ok: u}); !ok { + return + } } nextLink = users.NextLink @@ -89,23 +94,33 @@ func (s *azureClient) ListAzureADUsers(ctx context.Context, filter string, searc var users azure.UserList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if res, err := s.msgraph.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if err := rest.Decode(res.Body, &users); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else { for _, u := range users.Value { - out <- azure.UserResult{Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.UserResult{Ok: u}); !ok { + return + } } nextLink = users.NextLink } diff --git a/client/virtual_machines.go b/client/virtual_machines.go index a09f5fc..ccb810c 100644 --- a/client/virtual_machines.go +++ b/client/virtual_machines.go @@ -25,6 +25,7 @@ import ( "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/pipeline" ) func (s *azureClient) GetAzureVirtualMachine(ctx context.Context, subscriptionId, groupName, vmName, expand string) (*azure.VirtualMachine, error) { @@ -75,10 +76,14 @@ func (s *azureClient) ListAzureVirtualMachines(ctx context.Context, subscription if result, err := s.GetAzureVirtualMachines(ctx, subscriptionId, statusOnly); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range result.Value { - out <- azure.VirtualMachineResult{SubscriptionId: subscriptionId, Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.VirtualMachineResult{SubscriptionId: subscriptionId, Ok: u}); !ok { + return + } } nextLink = result.NextLink @@ -86,25 +91,35 @@ func (s *azureClient) ListAzureVirtualMachines(ctx context.Context, subscription var list azure.VirtualMachineList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if res, err := s.resourceManager.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if err := rest.Decode(res.Body, &list); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else { for _, u := range list.Value { - out <- azure.VirtualMachineResult{ + if ok := pipeline.Send(ctx.Done(), out, azure.VirtualMachineResult{ SubscriptionId: "/subscriptions/" + subscriptionId, Ok: u, + }); !ok { + return } } nextLink = list.NextLink diff --git a/client/vm_scale_sets.go b/client/vm_scale_sets.go index 2a443b3..4158553 100644 --- a/client/vm_scale_sets.go +++ b/client/vm_scale_sets.go @@ -25,6 +25,7 @@ import ( "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/pipeline" ) func (s *azureClient) GetAzureVMScaleSet(ctx context.Context, subscriptionId, groupName, vmssName, expand string) (*azure.VMScaleSet, error) { @@ -75,10 +76,14 @@ func (s *azureClient) ListAzureVMScaleSets(ctx context.Context, subscriptionId s if result, err := s.GetAzureVMScaleSets(ctx, subscriptionId, statusOnly); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range result.Value { - out <- azure.VMScaleSetResult{SubscriptionId: subscriptionId, Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.VMScaleSetResult{SubscriptionId: subscriptionId, Ok: u}); !ok { + return + } } nextLink = result.NextLink @@ -86,25 +91,35 @@ func (s *azureClient) ListAzureVMScaleSets(ctx context.Context, subscriptionId s var list azure.VMScaleSetList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if res, err := s.resourceManager.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if err := rest.Decode(res.Body, &list); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else { for _, u := range list.Value { - out <- azure.VMScaleSetResult{ + if ok := pipeline.Send(ctx.Done(), out, azure.VMScaleSetResult{ SubscriptionId: "/subscriptions/" + subscriptionId, Ok: u, + }); !ok { + return } } nextLink = list.NextLink diff --git a/client/web_apps.go b/client/web_apps.go index 3175250..7560d23 100644 --- a/client/web_apps.go +++ b/client/web_apps.go @@ -25,6 +25,7 @@ import ( "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/pipeline" ) func (s *azureClient) GetAzureWebApp(ctx context.Context, subscriptionId, groupName, waName, expand string) (*azure.WebApp, error) { @@ -75,10 +76,14 @@ func (s *azureClient) ListAzureWebApps(ctx context.Context, subscriptionId strin if result, err := s.GetAzureWebApps(ctx, subscriptionId); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } } else { for _, u := range result.Value { - out <- azure.WebAppResult{SubscriptionId: subscriptionId, Ok: u} + if ok := pipeline.Send(ctx.Done(), out, azure.WebAppResult{SubscriptionId: subscriptionId, Ok: u}); !ok { + return + } } nextLink = result.NextLink @@ -86,25 +91,35 @@ func (s *azureClient) ListAzureWebApps(ctx context.Context, subscriptionId strin var list azure.WebAppList if url, err := url.Parse(nextLink); err != nil { errResult.Error = err - out <- errResult + 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 - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if res, err := s.resourceManager.Send(req); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else if err := rest.Decode(res.Body, &list); err != nil { errResult.Error = err - out <- errResult + if ok := pipeline.Send(ctx.Done(), out, errResult); !ok { + return + } nextLink = "" } else { for _, u := range list.Value { - out <- azure.WebAppResult{ + if ok := pipeline.Send(ctx.Done(), out, azure.WebAppResult{ SubscriptionId: "/subscriptions/" + subscriptionId, Ok: u, + }); !ok { + return } } nextLink = list.NextLink diff --git a/cmd/list-app-owners.go b/cmd/list-app-owners.go index de137ca..869f03b 100644 --- a/cmd/list-app-owners.go +++ b/cmd/list-app-owners.go @@ -89,10 +89,12 @@ func listAppOwners(ctx context.Context, client client.AzureClient, apps <-chan a } } - out <- NewAzureWrapper( + if ok := pipeline.Send(ctx.Done(), out, NewAzureWrapper( enums.KindAZAppOwner, data, - ) + )); !ok { + return + } log.V(1).Info("finished listing app owners", "appId", app.Data.AppId, "count", count) } }() diff --git a/cmd/list-app-role-assignments.go b/cmd/list-app-role-assignments.go index 3672548..0cb2a52 100644 --- a/cmd/list-app-role-assignments.go +++ b/cmd/list-app-role-assignments.go @@ -75,7 +75,9 @@ func listAppRoleAssignments(ctx context.Context, client client.AzureClient, serv return } else { if len(servicePrincipal.AppRoles) != 0 { - filteredSPs <- servicePrincipal + if ok := pipeline.Send(ctx.Done(), filteredSPs, servicePrincipal); !ok { + return + } } } } @@ -96,13 +98,15 @@ func listAppRoleAssignments(ctx context.Context, client client.AzureClient, serv } else { log.V(2).Info("found app role assignment", "roleAssignments", item) count++ - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZAppRoleAssignment, Data: models.AppRoleAssignment{ AppRoleAssignment: item.Ok, AppId: servicePrincipal.AppId, TenantId: client.TenantInfo().TenantId, }, + }); !ok { + return } } } diff --git a/cmd/list-apps.go b/cmd/list-apps.go index 67bfd9f..76f7e59 100644 --- a/cmd/list-apps.go +++ b/cmd/list-apps.go @@ -26,6 +26,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -67,14 +68,16 @@ func listApps(ctx context.Context, client client.AzureClient) <-chan azureWrappe } else { log.V(2).Info("found application", "app", item) count++ - out <- NewAzureWrapper( + if ok := pipeline.Send(ctx.Done(), out, NewAzureWrapper( enums.KindAZApp, models.App{ Application: item.Ok, TenantId: client.TenantInfo().TenantId, TenantName: client.TenantInfo().DisplayName, }, - ) + )); !ok { + return + } } } log.Info("finished listing all apps", "count", count) diff --git a/cmd/list-automation-account-role-assignments.go b/cmd/list-automation-account-role-assignments.go index b1d74fc..f0bbcff 100644 --- a/cmd/list-automation-account-role-assignments.go +++ b/cmd/list-automation-account-role-assignments.go @@ -75,7 +75,9 @@ func listAutomationAccountRoleAssignments(ctx context.Context, client client.Azu log.Error(fmt.Errorf("failed type assertion"), "unable to continue enumerating automation account role assignments", "result", result) return } else { - ids <- automationAccount.Id + if ok := pipeline.Send(ctx.Done(), ids, automationAccount.Id); !ok { + return + } } } }() @@ -108,9 +110,11 @@ func listAutomationAccountRoleAssignments(ctx context.Context, client client.Azu automationAccountRoleAssignments.RoleAssignments = append(automationAccountRoleAssignments.RoleAssignments, automationAccountRoleAssignment) } } - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZAutomationAccountRoleAssignment, Data: automationAccountRoleAssignments, + }); !ok { + return } log.V(1).Info("finished listing automation account role assignments", "automationAccountId", id, "count", count) } diff --git a/cmd/list-automation-accounts.go b/cmd/list-automation-accounts.go index ebdc1f1..cf38396 100644 --- a/cmd/list-automation-accounts.go +++ b/cmd/list-automation-accounts.go @@ -72,7 +72,9 @@ func listAutomationAccounts(ctx context.Context, client client.AzureClient, subs log.Error(fmt.Errorf("failed type assertion"), "unable to continue enumerating automation accounts", "result", result) return } else { - ids <- subscription.SubscriptionId + if ok := pipeline.Send(ctx.Done(), ids, subscription.SubscriptionId); !ok { + return + } } } }() @@ -97,9 +99,11 @@ func listAutomationAccounts(ctx context.Context, client client.AzureClient, subs } log.V(2).Info("found automation account", "automationAccount", automationAccount) count++ - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZAutomationAccount, Data: automationAccount, + }); !ok { + return } } } diff --git a/cmd/list-container-registries.go b/cmd/list-container-registries.go index fcfd7b2..2ed3e4f 100644 --- a/cmd/list-container-registries.go +++ b/cmd/list-container-registries.go @@ -77,7 +77,9 @@ func listContainerRegistries(ctx context.Context, client client.AzureClient, sub log.Error(fmt.Errorf("failed type assertion"), "unable to continue enumerating container registries", "result", result) return } else { - ids <- subscription.SubscriptionId + if ok := pipeline.Send(ctx.Done(), ids, subscription.SubscriptionId); !ok { + return + } } } }() @@ -102,9 +104,11 @@ func listContainerRegistries(ctx context.Context, client client.AzureClient, sub } log.V(2).Info("found container registry", "containerRegistry", containerRegistry) count++ - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZContainerRegistry, Data: containerRegistry, + }); !ok { + return } } } diff --git a/cmd/list-container-registry-role-assignments.go b/cmd/list-container-registry-role-assignments.go index 32fd56e..4cfdf12 100644 --- a/cmd/list-container-registry-role-assignments.go +++ b/cmd/list-container-registry-role-assignments.go @@ -80,7 +80,9 @@ func listContainerRegistryRoleAssignments(ctx context.Context, client client.Azu log.Error(fmt.Errorf("failed type assertion"), "unable to continue enumerating container registry role assignments", "result", result) return } else { - ids <- containerRegistry.Id + if ok := pipeline.Send(ctx.Done(), ids, containerRegistry.Id); !ok { + return + } } } }() @@ -113,9 +115,11 @@ func listContainerRegistryRoleAssignments(ctx context.Context, client client.Azu containerRegistryRoleAssignments.RoleAssignments = append(containerRegistryRoleAssignments.RoleAssignments, containerRegistryRoleAssignment) } } - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZContainerRegistryRoleAssignment, Data: containerRegistryRoleAssignments, + }); !ok { + return } log.V(1).Info("finished listing container registry role assignments", "containerRegistryId", id, "count", count) } diff --git a/cmd/list-device-owners.go b/cmd/list-device-owners.go index be04b8a..124c646 100644 --- a/cmd/list-device-owners.go +++ b/cmd/list-device-owners.go @@ -72,7 +72,9 @@ func listDeviceOwners(ctx context.Context, client client.AzureClient, devices <- if device, ok := result.(AzureWrapper).Data.(models.Device); !ok { log.Error(fmt.Errorf("failed type assertion"), "unable to continue enumerating device owners", "result", result) } else { - ids <- device.Id + if ok := pipeline.Send(ctx.Done(), ids, device.Id); !ok { + return + } } } }() @@ -102,9 +104,11 @@ func listDeviceOwners(ctx context.Context, client client.AzureClient, devices <- data.Owners = append(data.Owners, deviceOwner) } } - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZDeviceOwner, Data: data, + }); !ok { + return } log.V(1).Info("finished listing device owners", "deviceId", id, "count", count) } diff --git a/cmd/list-devices.go b/cmd/list-devices.go index f185d49..37ccbb6 100644 --- a/cmd/list-devices.go +++ b/cmd/list-devices.go @@ -26,6 +26,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -67,13 +68,15 @@ func listDevices(ctx context.Context, client client.AzureClient) <-chan interfac } else { log.V(2).Info("found device", "device", item) count++ - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZDevice, Data: models.Device{ Device: item.Ok, TenantId: client.TenantInfo().TenantId, TenantName: client.TenantInfo().DisplayName, }, + }); !ok { + return } } } diff --git a/cmd/list-function-app-role-assignments.go b/cmd/list-function-app-role-assignments.go index 7cf539f..7433e75 100644 --- a/cmd/list-function-app-role-assignments.go +++ b/cmd/list-function-app-role-assignments.go @@ -75,7 +75,9 @@ func listFunctionAppRoleAssignments(ctx context.Context, client client.AzureClie log.Error(fmt.Errorf("failed type assertion"), "unable to continue enumerating function app role assignments", "result", result) return } else { - ids <- functionApp.Id + if ok := pipeline.Send(ctx.Done(), ids, functionApp.Id); !ok { + return + } } } }() @@ -108,9 +110,11 @@ func listFunctionAppRoleAssignments(ctx context.Context, client client.AzureClie functionAppRoleAssignments.RoleAssignments = append(functionAppRoleAssignments.RoleAssignments, functionAppRoleAssignment) } } - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZFunctionAppRoleAssignment, Data: functionAppRoleAssignments, + }); !ok { + return } log.V(1).Info("finished listing function app role assignments", "functionAppId", id, "count", count) } diff --git a/cmd/list-function-apps.go b/cmd/list-function-apps.go index eb147e9..a63e453 100644 --- a/cmd/list-function-apps.go +++ b/cmd/list-function-apps.go @@ -72,7 +72,9 @@ func listFunctionApps(ctx context.Context, client client.AzureClient, subscripti log.Error(fmt.Errorf("failed type assertion"), "unable to continue enumerating function apps", "result", result) return } else { - ids <- subscription.SubscriptionId + if ok := pipeline.Send(ctx.Done(), ids, subscription.SubscriptionId); !ok { + return + } } } }() @@ -98,9 +100,11 @@ func listFunctionApps(ctx context.Context, client client.AzureClient, subscripti if functionApp.Kind == "functionapp" { log.V(2).Info("found function app", "functionApp", functionApp) count++ - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZFunctionApp, Data: functionApp, + }); !ok { + return } } } diff --git a/cmd/list-group-members.go b/cmd/list-group-members.go index ce6ced6..cfdd203 100644 --- a/cmd/list-group-members.go +++ b/cmd/list-group-members.go @@ -73,7 +73,9 @@ func listGroupMembers(ctx context.Context, client client.AzureClient, groups <-c log.Error(fmt.Errorf("failed group type assertion"), "unable to continue enumerating group members", "result", result) return } else { - ids <- group.Id + if ok := pipeline.Send(ctx.Done(), ids, group.Id); !ok { + return + } } } }() @@ -103,9 +105,11 @@ func listGroupMembers(ctx context.Context, client client.AzureClient, groups <-c data.Members = append(data.Members, groupMember) } } - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZGroupMember, Data: data, + }); !ok { + return } log.V(1).Info("finished listing group memberships", "groupId", id, "count", count) } diff --git a/cmd/list-group-owners.go b/cmd/list-group-owners.go index a45834b..6bd171d 100644 --- a/cmd/list-group-owners.go +++ b/cmd/list-group-owners.go @@ -73,7 +73,9 @@ func listGroupOwners(ctx context.Context, client client.AzureClient, groups <-ch log.Error(fmt.Errorf("failed type assertion"), "unable to continue enumerating group owners", "result", result) return } else { - ids <- group.Id + if ok := pipeline.Send(ctx.Done(), ids, group.Id); !ok { + return + } } } }() @@ -103,9 +105,11 @@ func listGroupOwners(ctx context.Context, client client.AzureClient, groups <-ch groupOwners.Owners = append(groupOwners.Owners, groupOwner) } } - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZGroupOwner, Data: groupOwners, + }); !ok { + return } log.V(1).Info("finished listing group owners", "groupId", id, "count", count) } diff --git a/cmd/list-groups.go b/cmd/list-groups.go index e6632c5..21e321a 100644 --- a/cmd/list-groups.go +++ b/cmd/list-groups.go @@ -26,6 +26,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -72,9 +73,11 @@ func listGroups(ctx context.Context, client client.AzureClient) <-chan interface TenantId: client.TenantInfo().TenantId, TenantName: client.TenantInfo().DisplayName, } - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZGroup, Data: group, + }); !ok { + return } } } diff --git a/cmd/list-key-vault-access-policies.go b/cmd/list-key-vault-access-policies.go index 79c9c94..a7438e1 100644 --- a/cmd/list-key-vault-access-policies.go +++ b/cmd/list-key-vault-access-policies.go @@ -80,12 +80,14 @@ func listKeyVaultAccessPolicies(ctx context.Context, client client.AzureClient, } else { for _, policy := range keyVault.Properties.AccessPolicies { if len(filters) == 0 { - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: kinds.KindAZKeyVaultAccessPolicy, Data: models.KeyVaultAccessPolicy{ KeyVaultId: keyVault.Id, AccessPolicyEntry: policy, }, + }); !ok { + return } } else { for _, filter := range filters { @@ -103,12 +105,14 @@ func listKeyVaultAccessPolicies(ctx context.Context, client client.AzureClient, } }() if contains(permissions, "Get") { - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: kinds.KindAZKeyVaultAccessPolicy, Data: models.KeyVaultAccessPolicy{ KeyVaultId: keyVault.Id, AccessPolicyEntry: policy, }, + }); !ok { + return } break } diff --git a/cmd/list-key-vault-role-assignments.go b/cmd/list-key-vault-role-assignments.go index c9f0070..ee14b05 100644 --- a/cmd/list-key-vault-role-assignments.go +++ b/cmd/list-key-vault-role-assignments.go @@ -74,7 +74,9 @@ func listKeyVaultRoleAssignments(ctx context.Context, client client.AzureClient, log.Error(fmt.Errorf("failed type assertion"), "unable to continue enumerating key vault role assignments", "result", result) return } else { - ids <- keyVault.Id + if ok := pipeline.Send(ctx.Done(), ids, keyVault.Id); !ok { + return + } } } }() @@ -104,7 +106,9 @@ func listKeyVaultRoleAssignments(ctx context.Context, client client.AzureClient, keyVaultRoleAssignments.RoleAssignments = append(keyVaultRoleAssignments.RoleAssignments, keyVaultRoleAssignment) } } - out <- NewAzureWrapper(enums.KindAZKeyVaultRoleAssignment, keyVaultRoleAssignments) + if ok := pipeline.Send(ctx.Done(), out, NewAzureWrapper(enums.KindAZKeyVaultRoleAssignment, keyVaultRoleAssignments)); !ok { + return + } log.V(1).Info("finished listing key vault role assignments", "keyVaultId", id, "count", count) } }() diff --git a/cmd/list-key-vaults.go b/cmd/list-key-vaults.go index 90cd52a..dee1bcb 100644 --- a/cmd/list-key-vaults.go +++ b/cmd/list-key-vaults.go @@ -73,7 +73,9 @@ func listKeyVaults(ctx context.Context, client client.AzureClient, subscriptions log.Error(fmt.Errorf("failed type assertion"), "unable to continue enumerating key vaults", "result", result) return } else { - ids <- subscription.SubscriptionId + if ok := pipeline.Send(ctx.Done(), ids, subscription.SubscriptionId); !ok { + return + } } } }() @@ -100,9 +102,11 @@ func listKeyVaults(ctx context.Context, client client.AzureClient, subscriptions } log.V(2).Info("found key vault", "keyVault", keyVault) count++ - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZKeyVault, Data: keyVault, + }); !ok { + return } } } diff --git a/cmd/list-logic-app-role-assignments.go b/cmd/list-logic-app-role-assignments.go index 83e9df6..ed73508 100644 --- a/cmd/list-logic-app-role-assignments.go +++ b/cmd/list-logic-app-role-assignments.go @@ -80,7 +80,9 @@ func listLogicAppRoleAssignments(ctx context.Context, client client.AzureClient, log.Error(fmt.Errorf("failed type assertion"), "unable to continue enumerating logic app role assignments", "result", result) return } else { - ids <- logicapp.Id + if ok := pipeline.Send(ctx.Done(), ids, logicapp.Id); !ok { + return + } } } }() @@ -113,9 +115,11 @@ func listLogicAppRoleAssignments(ctx context.Context, client client.AzureClient, logicappRoleAssignments.RoleAssignments = append(logicappRoleAssignments.RoleAssignments, logicappRoleAssignment) } } - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZLogicAppRoleAssignment, Data: logicappRoleAssignments, + }); !ok { + return } log.V(1).Info("finished listing logic app role assignments", "logicappId", id, "count", count) } diff --git a/cmd/list-logic-apps.go b/cmd/list-logic-apps.go index 6bd54e1..a928634 100644 --- a/cmd/list-logic-apps.go +++ b/cmd/list-logic-apps.go @@ -77,7 +77,9 @@ func listLogicApps(ctx context.Context, client client.AzureClient, subscriptions log.Error(fmt.Errorf("failed type assertion"), "unable to continue enumerating logic apps", "result", result) return } else { - ids <- subscription.SubscriptionId + if ok := pipeline.Send(ctx.Done(), ids, subscription.SubscriptionId); !ok { + return + } } } }() @@ -107,9 +109,11 @@ func listLogicApps(ctx context.Context, client client.AzureClient, subscriptions } log.V(2).Info("found logicapp", "logicapp", logicapp) count++ - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZLogicApp, Data: logicapp, + }); !ok { + return } } } diff --git a/cmd/list-managed-cluster-role-assignments.go b/cmd/list-managed-cluster-role-assignments.go index 0ba6b1e..323df75 100644 --- a/cmd/list-managed-cluster-role-assignments.go +++ b/cmd/list-managed-cluster-role-assignments.go @@ -80,7 +80,9 @@ func listManagedClusterRoleAssignments(ctx context.Context, client client.AzureC log.Error(fmt.Errorf("failed type assertion"), "unable to continue enumerating managed cluster role assignments", "result", result) return } else { - ids <- managedCluster.Id + if ok := pipeline.Send(ctx.Done(), ids, managedCluster.Id); !ok { + return + } } } }() @@ -113,9 +115,11 @@ func listManagedClusterRoleAssignments(ctx context.Context, client client.AzureC managedClusterRoleAssignments.RoleAssignments = append(managedClusterRoleAssignments.RoleAssignments, managedClusterRoleAssignment) } } - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZManagedClusterRoleAssignment, Data: managedClusterRoleAssignments, + }); !ok { + return } log.V(1).Info("finished listing managed cluster role assignments", "managedClusterId", id, "count", count) } diff --git a/cmd/list-managed-clusters.go b/cmd/list-managed-clusters.go index b072a3c..3384e61 100644 --- a/cmd/list-managed-clusters.go +++ b/cmd/list-managed-clusters.go @@ -77,7 +77,9 @@ func listManagedClusters(ctx context.Context, client client.AzureClient, subscri log.Error(fmt.Errorf("failed type assertion"), "unable to continue enumerating managed clusters", "result", result) return } else { - ids <- subscription.SubscriptionId + if ok := pipeline.Send(ctx.Done(), ids, subscription.SubscriptionId); !ok { + return + } } } }() @@ -102,9 +104,11 @@ func listManagedClusters(ctx context.Context, client client.AzureClient, subscri } log.V(2).Info("found managed cluster", "managedCluster", managedCluster) count++ - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZManagedCluster, Data: managedCluster, + }); !ok { + return } } } diff --git a/cmd/list-management-group-descendants.go b/cmd/list-management-group-descendants.go index 33a05cf..904c11e 100644 --- a/cmd/list-management-group-descendants.go +++ b/cmd/list-management-group-descendants.go @@ -73,7 +73,9 @@ func listManagementGroupDescendants(ctx context.Context, client client.AzureClie log.Error(fmt.Errorf("failed type assertion"), "unable to continue enumerating management group descendants", "result", result) return } else { - ids <- managementGroup.Name + if ok := pipeline.Send(ctx.Done(), ids, managementGroup.Name); !ok { + return + } } } }() @@ -91,9 +93,11 @@ func listManagementGroupDescendants(ctx context.Context, client client.AzureClie } else { log.V(2).Info("found management group descendant", "type", item.Ok.Type, "id", item.Ok.Id, "parent", item.Ok.Properties.Parent.Id) count++ - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZManagementGroupDescendant, Data: item.Ok, + }); !ok { + return } } } diff --git a/cmd/list-management-group-role-assignments.go b/cmd/list-management-group-role-assignments.go index 0a2bb76..3d07121 100644 --- a/cmd/list-management-group-role-assignments.go +++ b/cmd/list-management-group-role-assignments.go @@ -74,7 +74,9 @@ func listManagementGroupRoleAssignments(ctx context.Context, client client.Azure log.Error(fmt.Errorf("failed type assertion"), "unable to continue enumerating management group role assignments", "result", result) return } else { - ids <- managementGroup.Id + if ok := pipeline.Send(ctx.Done(), ids, managementGroup.Id); !ok { + return + } } } }() @@ -104,10 +106,12 @@ func listManagementGroupRoleAssignments(ctx context.Context, client client.Azure managementGroupRoleAssignments.RoleAssignments = append(managementGroupRoleAssignments.RoleAssignments, managementGroupRoleAssignment) } } - out <- NewAzureWrapper( + if ok := pipeline.Send(ctx.Done(), out, NewAzureWrapper( enums.KindAZManagementGroupRoleAssignment, managementGroupRoleAssignments, - ) + )); !ok { + return + } log.V(1).Info("finished listing managementGroup role assignments", "managementGroupId", id, "count", count) } }() diff --git a/cmd/list-management-groups.go b/cmd/list-management-groups.go index 66b1f46..2d02e5f 100644 --- a/cmd/list-management-groups.go +++ b/cmd/list-management-groups.go @@ -27,6 +27,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/config" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -74,9 +75,11 @@ func listManagementGroups(ctx context.Context, client client.AzureClient) <-chan TenantName: client.TenantInfo().DisplayName, } - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZManagementGroup, Data: mgmtGroup, + }); !ok { + return } } } diff --git a/cmd/list-resource-group-role-assignments.go b/cmd/list-resource-group-role-assignments.go index a44fd8a..055d3e0 100644 --- a/cmd/list-resource-group-role-assignments.go +++ b/cmd/list-resource-group-role-assignments.go @@ -75,7 +75,9 @@ func listResourceGroupRoleAssignments(ctx context.Context, client client.AzureCl log.Error(fmt.Errorf("failed type assertion"), "unable to continue enumerating resource group role assignments", "result", result) return } else { - ids <- resourceGroup.Id + if ok := pipeline.Send(ctx.Done(), ids, resourceGroup.Id); !ok { + return + } } } }() @@ -105,7 +107,9 @@ func listResourceGroupRoleAssignments(ctx context.Context, client client.AzureCl resourceGroupRoleAssignments.RoleAssignments = append(resourceGroupRoleAssignments.RoleAssignments, resourceGroupRoleAssignment) } } - out <- NewAzureWrapper(enums.KindAZResourceGroupRoleAssignment, resourceGroupRoleAssignments) + if ok := pipeline.Send(ctx.Done(), out, NewAzureWrapper(enums.KindAZResourceGroupRoleAssignment, resourceGroupRoleAssignments)); !ok { + return + } log.V(1).Info("finished listing resourceGroup role assignments", "resourceGroupId", id, "count", count) } }() diff --git a/cmd/list-resource-groups.go b/cmd/list-resource-groups.go index 7299852..5f83d56 100644 --- a/cmd/list-resource-groups.go +++ b/cmd/list-resource-groups.go @@ -73,7 +73,9 @@ func listResourceGroups(ctx context.Context, client client.AzureClient, subscrip log.Error(fmt.Errorf("failed type assertion"), "unable to continue enumerating resource groups", "result", result) return } else { - ids <- subscription.SubscriptionId + if ok := pipeline.Send(ctx.Done(), ids, subscription.SubscriptionId); !ok { + return + } } } }() @@ -96,9 +98,11 @@ func listResourceGroups(ctx context.Context, client client.AzureClient, subscrip } log.V(2).Info("found resource group", "resourceGroup", resourceGroup) count++ - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZResourceGroup, Data: resourceGroup, + }); !ok { + return } } } diff --git a/cmd/list-role-assignments.go b/cmd/list-role-assignments.go index 8348fd7..0289c9e 100644 --- a/cmd/list-role-assignments.go +++ b/cmd/list-role-assignments.go @@ -74,7 +74,9 @@ func listRoleAssignments(ctx context.Context, client client.AzureClient, roles < log.Error(fmt.Errorf("failed type assertion"), "unable to continue enumerating role assignments", "result", result) return } else { - ids <- role.Id + if ok := pipeline.Send(ctx.Done(), ids, role.Id); !ok { + return + } } } }() @@ -102,9 +104,11 @@ func listRoleAssignments(ctx context.Context, client client.AzureClient, roles < roleAssignments.RoleAssignments = append(roleAssignments.RoleAssignments, item.Ok) } } - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZRoleAssignment, Data: roleAssignments, + }); !ok { + return } log.V(1).Info("finished listing role assignments", "roleDefinitionId", id, "count", count) } diff --git a/cmd/list-roles.go b/cmd/list-roles.go index 23db917..ab93352 100644 --- a/cmd/list-roles.go +++ b/cmd/list-roles.go @@ -26,6 +26,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -67,13 +68,15 @@ func listRoles(ctx context.Context, client client.AzureClient) <-chan interface{ } else { log.V(2).Info("found role", "role", item) count++ - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZRole, Data: models.Role{ Role: item.Ok, TenantId: client.TenantInfo().TenantId, TenantName: client.TenantInfo().DisplayName, }, + }); !ok { + return } } } diff --git a/cmd/list-service-principal-owners.go b/cmd/list-service-principal-owners.go index 845d30d..5e07aed 100644 --- a/cmd/list-service-principal-owners.go +++ b/cmd/list-service-principal-owners.go @@ -73,7 +73,9 @@ func listServicePrincipalOwners(ctx context.Context, client client.AzureClient, log.Error(fmt.Errorf("failed type assertion"), "unable to continue enumerating service principal owners", "result", result) return } else { - ids <- servicePrincipal.Id + if ok := pipeline.Send(ctx.Done(), ids, servicePrincipal.Id); !ok { + return + } } } }() @@ -103,9 +105,11 @@ func listServicePrincipalOwners(ctx context.Context, client client.AzureClient, servicePrincipalOwners.Owners = append(servicePrincipalOwners.Owners, servicePrincipalOwner) } } - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZServicePrincipalOwner, Data: servicePrincipalOwners, + }); !ok { + return } log.V(1).Info("finished listing service principal owners", "servicePrincipalId", id, "count", count) } diff --git a/cmd/list-service-principals.go b/cmd/list-service-principals.go index bf7aecf..80500e9 100644 --- a/cmd/list-service-principals.go +++ b/cmd/list-service-principals.go @@ -26,6 +26,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -67,13 +68,15 @@ func listServicePrincipals(ctx context.Context, client client.AzureClient) <-cha } else { log.V(2).Info("found service principal", "servicePrincipal", item) count++ - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZServicePrincipal, Data: models.ServicePrincipal{ ServicePrincipal: item.Ok, TenantId: client.TenantInfo().TenantId, TenantName: client.TenantInfo().DisplayName, }, + }); !ok { + return } } } diff --git a/cmd/list-storage-account-role-assignments.go b/cmd/list-storage-account-role-assignments.go index b049dd8..4e5d0bc 100644 --- a/cmd/list-storage-account-role-assignments.go +++ b/cmd/list-storage-account-role-assignments.go @@ -75,7 +75,9 @@ func listStorageAccountRoleAssignments(ctx context.Context, client client.AzureC log.Error(fmt.Errorf("failed type assertion"), "unable to continue enumerating storage account role assignments", "result", result) return } else { - ids <- storageAccount.Id + if ok := pipeline.Send(ctx.Done(), ids, storageAccount.Id); !ok { + return + } } } }() @@ -108,9 +110,11 @@ func listStorageAccountRoleAssignments(ctx context.Context, client client.AzureC storageAccountRoleAssignments.RoleAssignments = append(storageAccountRoleAssignments.RoleAssignments, storageAccountRoleAssignment) } } - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZStorageAccountRoleAssignment, Data: storageAccountRoleAssignments, + }); !ok { + return } log.V(1).Info("finished listing storage account role assignments", "storageAccountId", id, "count", count) } diff --git a/cmd/list-storage-accounts.go b/cmd/list-storage-accounts.go index fd22ec1..143a645 100644 --- a/cmd/list-storage-accounts.go +++ b/cmd/list-storage-accounts.go @@ -72,7 +72,9 @@ func listStorageAccounts(ctx context.Context, client client.AzureClient, subscri log.Error(fmt.Errorf("failed type assertion"), "unable to continue enumerating storage accounts", "result", result) return } else { - ids <- subscription.SubscriptionId + if ok := pipeline.Send(ctx.Done(), ids, subscription.SubscriptionId); !ok { + return + } } } }() @@ -99,9 +101,11 @@ func listStorageAccounts(ctx context.Context, client client.AzureClient, subscri } log.V(2).Info("found storage account", "storageAccount", storageAccount) count++ - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZStorageAccount, Data: storageAccount, + }); !ok { + return } } } diff --git a/cmd/list-storage-containers.go b/cmd/list-storage-containers.go index 66e461d..08b04d1 100644 --- a/cmd/list-storage-containers.go +++ b/cmd/list-storage-containers.go @@ -79,7 +79,9 @@ func listStorageContainers(ctx context.Context, client client.AzureClient, stora log.Error(fmt.Errorf("failed type assertion"), "unable to continue enumerating storage containers", "result", result) return } else { - ids <- storageAccount + if ok := pipeline.SendAny(ctx.Done(), ids, storageAccount); !ok { + return + } } } }() @@ -107,9 +109,11 @@ func listStorageContainers(ctx context.Context, client client.AzureClient, stora } log.V(2).Info("found storage container", "storageContainer", storageContainer) count++ - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZStorageContainer, Data: storageContainer, + }); !ok { + return } } log.V(1).Info("finished listing storage containers", "subscriptionId", stAccount.(models.StorageAccount).SubscriptionId, "count", count) diff --git a/cmd/list-subscription-owners.go b/cmd/list-subscription-owners.go index 000e778..af7dd59 100644 --- a/cmd/list-subscription-owners.go +++ b/cmd/list-subscription-owners.go @@ -90,9 +90,11 @@ func listSubscriptionOwners(ctx context.Context, client client.AzureClient, role subscriptionOwners.Owners = append(subscriptionOwners.Owners, subscriptionOwner) } } - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZSubscriptionOwner, Data: subscriptionOwners, + }); !ok { + return } log.V(1).Info("finished listing subscription owners", "subscriptionId", roleAssignments.SubscriptionId, "count", count) } diff --git a/cmd/list-subscription-role-assignments.go b/cmd/list-subscription-role-assignments.go index 8e6dab3..3f23107 100644 --- a/cmd/list-subscription-role-assignments.go +++ b/cmd/list-subscription-role-assignments.go @@ -74,7 +74,9 @@ func listSubscriptionRoleAssignments(ctx context.Context, client client.AzureCli log.Error(fmt.Errorf("failed type assertion"), "unable to continue enumerating subscription role assignments", "result", result) return } else { - ids <- subscription.Id + if ok := pipeline.Send(ctx.Done(), ids, subscription.Id); !ok { + return + } } } }() @@ -104,9 +106,11 @@ func listSubscriptionRoleAssignments(ctx context.Context, client client.AzureCli subscriptionRoleAssignments.RoleAssignments = append(subscriptionRoleAssignments.RoleAssignments, subscriptionRoleAssignment) } } - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZSubscriptionRoleAssignment, Data: subscriptionRoleAssignments, + }); !ok { + return } log.V(1).Info("finished listing subscription role assignments", "subscriptionId", id, "count", count) } diff --git a/cmd/list-subscription-user-access-admins.go b/cmd/list-subscription-user-access-admins.go index 3502ed8..9947836 100644 --- a/cmd/list-subscription-user-access-admins.go +++ b/cmd/list-subscription-user-access-admins.go @@ -90,9 +90,11 @@ func listSubscriptionUserAccessAdmins(ctx context.Context, client client.AzureCl subscriptionUserAccessAdmins.UserAccessAdmins = append(subscriptionUserAccessAdmins.UserAccessAdmins, subscriptionUserAccessAdmin) } } - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZSubscriptionUserAccessAdmin, Data: subscriptionUserAccessAdmins, + }); !ok { + return } log.V(1).Info("finished listing subscription user access admins", "subscriptionId", roleAssignments.SubscriptionId, "count", count) } diff --git a/cmd/list-subscriptions.go b/cmd/list-subscriptions.go index b27fa7f..b2ee039 100644 --- a/cmd/list-subscriptions.go +++ b/cmd/list-subscriptions.go @@ -26,6 +26,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/models" "github.com/bloodhoundad/azurehound/v2/models/azure" + "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/config" @@ -96,9 +97,11 @@ func listSubscriptions(ctx context.Context, client client.AzureClient) <-chan in Subscription: item.Ok, } data.TenantId = client.TenantInfo().TenantId - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZSubscription, Data: data, + }); !ok { + return } } } diff --git a/cmd/list-tenants.go b/cmd/list-tenants.go index 128a8e8..438cb79 100644 --- a/cmd/list-tenants.go +++ b/cmd/list-tenants.go @@ -26,6 +26,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -62,12 +63,14 @@ func listTenants(ctx context.Context, client client.AzureClient) <-chan interfac // Send the fully hydrated tenant that is being collected collectedTenant := client.TenantInfo() - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZTenant, Data: models.Tenant{ Tenant: collectedTenant, Collected: true, }, + }); !ok { + return } count := 1 for item := range client.ListAzureADTenants(ctx, true) { @@ -80,11 +83,13 @@ func listTenants(ctx context.Context, client client.AzureClient) <-chan interfac // Send the remaining tenant trusts if item.Ok.TenantId != collectedTenant.TenantId { - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZTenant, Data: models.Tenant{ Tenant: item.Ok, }, + }); !ok { + return } } } diff --git a/cmd/list-users.go b/cmd/list-users.go index 7a71eca..e02e37a 100644 --- a/cmd/list-users.go +++ b/cmd/list-users.go @@ -26,6 +26,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -84,9 +85,11 @@ func listUsers(ctx context.Context, client client.AzureClient) <-chan interface{ TenantId: client.TenantInfo().TenantId, TenantName: client.TenantInfo().DisplayName, } - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZUser, Data: user, + }); !ok { + return } } } diff --git a/cmd/list-virtual-machine-role-assignments.go b/cmd/list-virtual-machine-role-assignments.go index 18346e7..d826a3f 100644 --- a/cmd/list-virtual-machine-role-assignments.go +++ b/cmd/list-virtual-machine-role-assignments.go @@ -74,7 +74,9 @@ func listVirtualMachineRoleAssignments(ctx context.Context, client client.AzureC log.Error(fmt.Errorf("failed type assertion"), "unable to continue enumerating virtual machine role assignments", "result", result) return } else { - ids <- virtualMachine.Id + if ok := pipeline.Send(ctx.Done(), ids, virtualMachine.Id); !ok { + return + } } } }() @@ -104,7 +106,9 @@ func listVirtualMachineRoleAssignments(ctx context.Context, client client.AzureC virtualMachineRoleAssignments.RoleAssignments = append(virtualMachineRoleAssignments.RoleAssignments, virtualMachineRoleAssignment) } } - out <- NewAzureWrapper(enums.KindAZVMRoleAssignment, virtualMachineRoleAssignments) + if ok := pipeline.Send(ctx.Done(), out, NewAzureWrapper(enums.KindAZVMRoleAssignment, virtualMachineRoleAssignments)); !ok { + return + } log.V(1).Info("finished listing virtual machine role assignments", "virtualMachineId", id, "count", count) } }() diff --git a/cmd/list-virtual-machines.go b/cmd/list-virtual-machines.go index 3f1597a..ad4b78e 100644 --- a/cmd/list-virtual-machines.go +++ b/cmd/list-virtual-machines.go @@ -72,7 +72,9 @@ func listVirtualMachines(ctx context.Context, client client.AzureClient, subscri log.Error(fmt.Errorf("failed type assertion"), "unable to continue enumerating virtual machines", "result", result) return } else { - ids <- subscription.SubscriptionId + if ok := pipeline.Send(ctx.Done(), ids, subscription.SubscriptionId); !ok { + return + } } } }() @@ -97,9 +99,11 @@ func listVirtualMachines(ctx context.Context, client client.AzureClient, subscri } log.V(2).Info("found virtual machine", "virtualMachine", virtualMachine) count++ - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZVM, Data: virtualMachine, + }); !ok { + return } } } diff --git a/cmd/list-vm-scale-set-role-assignments.go b/cmd/list-vm-scale-set-role-assignments.go index de6f3de..80c5a52 100644 --- a/cmd/list-vm-scale-set-role-assignments.go +++ b/cmd/list-vm-scale-set-role-assignments.go @@ -80,7 +80,9 @@ func listVMScaleSetRoleAssignments(ctx context.Context, client client.AzureClien log.Error(fmt.Errorf("failed type assertion"), "unable to continue enumerating vm scale set role assignments", "result", result) return } else { - ids <- vmScaleSet.Id + if ok := pipeline.Send(ctx.Done(), ids, vmScaleSet.Id); !ok { + return + } } } }() @@ -113,9 +115,11 @@ func listVMScaleSetRoleAssignments(ctx context.Context, client client.AzureClien vmScaleSetRoleAssignments.RoleAssignments = append(vmScaleSetRoleAssignments.RoleAssignments, vmScaleSetRoleAssignment) } } - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZVMScaleSetRoleAssignment, Data: vmScaleSetRoleAssignments, + }); !ok { + return } log.V(1).Info("finished listing vm scale set role assignments", "vmScaleSetId", id, "count", count) } diff --git a/cmd/list-vm-scale-sets.go b/cmd/list-vm-scale-sets.go index 8ddac92..9623a54 100644 --- a/cmd/list-vm-scale-sets.go +++ b/cmd/list-vm-scale-sets.go @@ -77,7 +77,9 @@ func listVMScaleSets(ctx context.Context, client client.AzureClient, subscriptio log.Error(fmt.Errorf("failed type assertion"), "unable to continue enumerating virtual machine scale sets", "result", result) return } else { - ids <- subscription.SubscriptionId + if ok := pipeline.Send(ctx.Done(), ids, subscription.SubscriptionId); !ok { + return + } } } }() @@ -102,9 +104,11 @@ func listVMScaleSets(ctx context.Context, client client.AzureClient, subscriptio } log.V(2).Info("found virtual machine scale set", "vmScaleSet", vmScaleSet) count++ - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZVMScaleSet, Data: vmScaleSet, + }); !ok { + return } } } diff --git a/cmd/list-web-app-role-assignments.go b/cmd/list-web-app-role-assignments.go index c47d96e..3b45efb 100644 --- a/cmd/list-web-app-role-assignments.go +++ b/cmd/list-web-app-role-assignments.go @@ -80,7 +80,9 @@ func listWebAppRoleAssignments(ctx context.Context, client client.AzureClient, w log.Error(fmt.Errorf("failed type assertion"), "unable to continue enumerating web app role assignments", "result", result) return } else { - ids <- webApp.Id + if ok := pipeline.Send(ctx.Done(), ids, webApp.Id); !ok { + return + } } } }() @@ -113,9 +115,11 @@ func listWebAppRoleAssignments(ctx context.Context, client client.AzureClient, w webAppRoleAssignments.RoleAssignments = append(webAppRoleAssignments.RoleAssignments, webAppRoleAssignment) } } - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZWebAppRoleAssignment, Data: webAppRoleAssignments, + }); !ok { + return } log.V(1).Info("finished listing web app role assignments", "webAppId", id, "count", count) } diff --git a/cmd/list-web-apps.go b/cmd/list-web-apps.go index 23152eb..ac1bad7 100644 --- a/cmd/list-web-apps.go +++ b/cmd/list-web-apps.go @@ -77,7 +77,9 @@ func listWebApps(ctx context.Context, client client.AzureClient, subscriptions < log.Error(fmt.Errorf("failed type assertion"), "unable to continue enumerating web apps", "result", result) return } else { - ids <- subscription.SubscriptionId + if ok := pipeline.Send(ctx.Done(), ids, subscription.SubscriptionId); !ok { + return + } } } }() @@ -103,9 +105,11 @@ func listWebApps(ctx context.Context, client client.AzureClient, subscriptions < if webApp.Kind == "app" { log.V(2).Info("found web app", "webApp", webApp) count++ - out <- AzureWrapper{ + if ok := pipeline.SendAny(ctx.Done(), out, AzureWrapper{ Kind: enums.KindAZWebApp, Data: webApp, + }); !ok { + return } } } diff --git a/pipeline/pipeline.go b/pipeline/pipeline.go index e909162..d4b4df5 100644 --- a/pipeline/pipeline.go +++ b/pipeline/pipeline.go @@ -31,6 +31,26 @@ type Result[T any] struct { Ok T } +// Send sends a value to a channel while monitoring the done channel for cancellation +func Send[D, T any](done <-chan D, tgt chan<- T, val T) bool { + select { + case tgt <- val: + return true + case <-done: + return false + } +} + +// SendAny sends a value to an any channel while monitoring the done channel for cancellation +func SendAny[T any](done <-chan T, tgt chan<- any, val any) bool { + select { + case tgt <- val: + return true + case <-done: + return false + } +} + // OrDone provides an explicit cancellation mechanism to ensure the encapsulated and downstream goroutines are cleaned // up. This frees the caller from depending on the input channel to close in order to free the goroutine, thus // preventing possible leaks. @@ -66,7 +86,9 @@ func Mux[D any](done <-chan D, channels ...<-chan any) <-chan any { muxer := func(channel <-chan any) { defer wg.Done() for item := range OrDone(done, channel) { - out <- item + if ok := Send(done, out, item); !ok { + return + } } } @@ -129,7 +151,9 @@ func Map[D, T, U any](done <-chan D, in <-chan T, fn func(T) U) <-chan U { go func() { defer close(out) for item := range OrDone(done, in) { - out <- fn(item) + if ok := Send(done, out, fn(item)); !ok { + return + } } }() return out @@ -141,7 +165,9 @@ func Filter[D, T any](done <-chan D, in <-chan T, fn func(T) bool) <-chan T { defer close(out) for item := range OrDone(done, in) { if fn(item) { - out <- item + if ok := Send(done, out, item); !ok { + return + } } } }() @@ -161,8 +187,9 @@ func Tee[D, T any](done <-chan D, in <-chan T, outputs ...chan T) { for item := range OrDone(done, in) { for _, out := range outputs { select { - case <-done: case out <- item: + case <-done: + return } } } @@ -190,15 +217,13 @@ func Batch[D, T any](done <-chan D, in <-chan T, maxItems int, maxTimeout time.D for { select { case <-done: - if len(batch) > 0 { - out <- batch - batch = nil - } return case item, ok := <-in: if !ok { if len(batch) > 0 { - out <- batch + if ok = Send(done, out, batch); !ok { + return + } batch = nil } return @@ -208,14 +233,18 @@ func Batch[D, T any](done <-chan D, in <-chan T, maxItems int, maxTimeout time.D // Flush if limit is reached if len(batch) >= maxItems { - out <- batch + if ok = Send(done, out, batch); !ok { + return + } batch = nil timeout = time.After(maxTimeout) } } case <-timeout: if len(batch) > 0 { - out <- batch + if ok := Send(done, out, batch); !ok { + return + } batch = nil } timeout = time.After(maxTimeout) @@ -236,7 +265,9 @@ func FormatJson[D, T any](done <-chan D, in <-chan T) <-chan string { if bytes, err := json.Marshal(item); err != nil { panic(err) } else { - out <- string(bytes) + if ok := Send(done, out, string(bytes)); !ok { + return + } } } }()