From 6d6676e0d85a4b273f9d77276f487ab1b23ab7bf Mon Sep 17 00:00:00 2001 From: jknudsen Date: Wed, 15 Nov 2023 15:08:38 +0100 Subject: [PATCH 1/4] fix: EnterpriseCA reg data ingest --- packages/go/ein/ad.go | 2 +- packages/go/ein/incoming_models.go | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/go/ein/ad.go b/packages/go/ein/ad.go index c11c91067..c53ff9cde 100644 --- a/packages/go/ein/ad.go +++ b/packages/go/ein/ad.go @@ -474,7 +474,7 @@ func handleEnterpriseCAEnrollmentAgentRestrictions(enterpriseCA EnterpriseCA, re func handleEnterpriseCASecurity(enterpriseCA EnterpriseCA, relationships []IngestibleRelationship) []IngestibleRelationship { - if enterpriseCA.CASecurity.Collected { + if enterpriseCA.CARegistryData.CASecurity.Collected { caSecurityData := slices.Filter(enterpriseCA.CARegistryData.CASecurity.Data, func(s ACE) bool { if s.RightName == ad.Owns.String() { return false diff --git a/packages/go/ein/incoming_models.go b/packages/go/ein/incoming_models.go index a59aebd50..1b55af1ce 100644 --- a/packages/go/ein/incoming_models.go +++ b/packages/go/ein/incoming_models.go @@ -121,9 +121,9 @@ type IsUserSpecifiesSanEnabled struct { } type CARegistryData struct { - CASecurity - EnrollmentAgentRestrictions - IsUserSpecifiesSanEnabled + CASecurity CASecurity + EnrollmentAgentRestrictions EnrollmentAgentRestrictions + IsUserSpecifiesSanEnabled IsUserSpecifiesSanEnabled } type DCRegistryData struct { @@ -152,7 +152,7 @@ type RootCA struct { type EnterpriseCA struct { IngestBase - CARegistryData + CARegistryData CARegistryData EnabledCertTemplates []TypedPrincipal HostingComputer string DomainSID string From b09e04d31e6e516466358c1d8af8713917db79c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=BClow=20Knudsen?= <12843299+JonasBK@users.noreply.github.com> Date: Wed, 15 Nov 2023 07:25:16 -0800 Subject: [PATCH 2/4] feat: add EnterpriseCA properties (#213) --- cmd/api/src/daemons/datapipe/convertors.go | 1 + cmd/ui/src/ducks/entityinfo/types.ts | 3 ++- packages/cue/bh/ad/ad.cue | 16 ++++++++++++ packages/go/ein/ad.go | 25 +++++++++++++++++++ packages/go/graphschema/ad/ad.go | 16 +++++++++++- .../bh-shared-ui/src/graphSchema.ts | 6 +++++ 6 files changed, 65 insertions(+), 2 deletions(-) diff --git a/cmd/api/src/daemons/datapipe/convertors.go b/cmd/api/src/daemons/datapipe/convertors.go index 64fce0cab..12423c3c3 100644 --- a/cmd/api/src/daemons/datapipe/convertors.go +++ b/cmd/api/src/daemons/datapipe/convertors.go @@ -219,6 +219,7 @@ func convertEnterpriseCAData(data []ein.EnterpriseCA) ConvertedData { for _, enterpriseca := range data { converted.NodeProps = append(converted.NodeProps, ein.ConvertObjectToNode(enterpriseca.IngestBase, ad.EnterpriseCA)) + converted.NodeProps = append(converted.NodeProps, ein.ParseCARegistryProperties(enterpriseca)) converted.RelProps = append(converted.RelProps, ein.ParseEnterpriseCAMiscData(enterpriseca)...) if rel := ein.ParseObjectContainer(enterpriseca.IngestBase, ad.EnterpriseCA); rel.IsValid() { diff --git a/cmd/ui/src/ducks/entityinfo/types.ts b/cmd/ui/src/ducks/entityinfo/types.ts index fb60f110f..60c6d0783 100644 --- a/cmd/ui/src/ducks/entityinfo/types.ts +++ b/cmd/ui/src/ducks/entityinfo/types.ts @@ -137,7 +137,8 @@ export interface EnterpriseCAInfo extends EntityInfo { enrollmentagentrestrictionscollected: boolean; flags: 10; hasbasicconstraints: boolean; - isuserspecifiessanenabled: boolean; + hasenrollmentagentrestrictions?: boolean; + isuserspecifiessanenabled?: boolean; isuserspecifiessanenabledcollected: boolean; description?: string; }; diff --git a/packages/cue/bh/ad/ad.cue b/packages/cue/bh/ad/ad.cue index a1762731c..810c3f0ac 100644 --- a/packages/cue/bh/ad/ad.cue +++ b/packages/cue/bh/ad/ad.cue @@ -69,6 +69,13 @@ CASecurityCollected: types.#StringEnum & { representation: "casecuritycollected" } +HasEnrollmentAgentRestrictions: types.#StringEnum & { + symbol: "HasEnrollmentAgentRestrictions" + schema: "ad" + name: "Has Enrollment Agent Restrictions" + representation: "hasenrollmentagentrestrictions" +} + EnrollmentAgentRestrictionsCollected: types.#StringEnum & { symbol: "EnrollmentAgentRestrictionsCollected" schema: "ad" @@ -76,6 +83,13 @@ EnrollmentAgentRestrictionsCollected: types.#StringEnum & { representation: "enrollmentagentrestrictionscollected" } +IsUserSpecifiesSanEnabled: types.#StringEnum & { + symbol: "IsUserSpecifiesSanEnabled" + schema: "ad" + name: "Is User Specifies San Enabled" + representation: "isuserspecifiessanenabled" +} + IsUserSpecifiesSanEnabledCollected: types.#StringEnum & { symbol: "IsUserSpecifiesSanEnabledCollected" schema: "ad" @@ -462,7 +476,9 @@ Properties: [ CertName, CertThumbprint, CertThumbprints, + HasEnrollmentAgentRestrictions, EnrollmentAgentRestrictionsCollected, + IsUserSpecifiesSanEnabled, IsUserSpecifiesSanEnabledCollected, HasBasicConstraints, BasicConstraintPathLength, diff --git a/packages/go/ein/ad.go b/packages/go/ein/ad.go index c53ff9cde..608871520 100644 --- a/packages/go/ein/ad.go +++ b/packages/go/ein/ad.go @@ -407,6 +407,31 @@ func ParseUserRightData(userRight UserRightsAssignmentAPIResult, computer Comput return relationships } +func ParseCARegistryProperties(enterpriseCA EnterpriseCA) IngestibleNode { + propMap := make(map[string]any) + + // HasEnrollmentAgentRestrictions + if enterpriseCA.CARegistryData.EnrollmentAgentRestrictions.Collected { + + if len(enterpriseCA.CARegistryData.EnrollmentAgentRestrictions.Restrictions) > 0 { + propMap[ad.HasEnrollmentAgentRestrictions.String()] = true + } else { + propMap[ad.HasEnrollmentAgentRestrictions.String()] = false + } + } + + // IsUserSpecifiesSanEnabled + if enterpriseCA.CARegistryData.IsUserSpecifiesSanEnabled.Collected { + propMap[ad.IsUserSpecifiesSanEnabled.String()] = enterpriseCA.CARegistryData.IsUserSpecifiesSanEnabled.Value + } + + return IngestibleNode{ + ObjectID: enterpriseCA.ObjectIdentifier, + PropertyMap: propMap, + Label: ad.EnterpriseCA, + } +} + func ParseEnterpriseCAMiscData(enterpriseCA EnterpriseCA) []IngestibleRelationship { var ( relationships = make([]IngestibleRelationship, 0) diff --git a/packages/go/graphschema/ad/ad.go b/packages/go/graphschema/ad/ad.go index 6f78e27ba..806ebceae 100644 --- a/packages/go/graphschema/ad/ad.go +++ b/packages/go/graphschema/ad/ad.go @@ -110,7 +110,9 @@ const ( CertName Property = "certname" CertThumbprint Property = "certthumbprint" CertThumbprints Property = "certthumbprints" + HasEnrollmentAgentRestrictions Property = "hasenrollmentagentrestrictions" EnrollmentAgentRestrictionsCollected Property = "enrollmentagentrestrictionscollected" + IsUserSpecifiesSanEnabled Property = "isuserspecifiessanenabled" IsUserSpecifiesSanEnabledCollected Property = "isuserspecifiessanenabledcollected" HasBasicConstraints Property = "hasbasicconstraints" BasicConstraintPathLength Property = "basicconstraintpathlength" @@ -167,7 +169,7 @@ const ( ) func AllProperties() []Property { - return []Property{AdminCount, CASecurityCollected, CAName, CertChain, CertName, CertThumbprint, CertThumbprints, EnrollmentAgentRestrictionsCollected, IsUserSpecifiesSanEnabledCollected, HasBasicConstraints, BasicConstraintPathLength, DNSHostname, CrossCertificatePair, DistinguishedName, DomainFQDN, DomainSID, Sensitive, HighValue, BlocksInheritance, IsACL, IsACLProtected, IsDeleted, Enforced, Department, HasCrossCertificatePair, HasSPN, UnconstrainedDelegation, LastLogon, LastLogonTimestamp, IsPrimaryGroup, HasLAPS, DontRequirePreAuth, LogonType, HasURA, PasswordNeverExpires, PasswordNotRequired, FunctionalLevel, TrustType, SidFiltering, TrustedToAuth, SamAccountName, CertificateMappingMethodsRaw, CertificateMappingMethods, StrongCertificateBindingEnforcementRaw, StrongCertificateBindingEnforcement, EKUs, SubjectAltRequireUPN, AuthorizedSignatures, ApplicationPolicies, SchemaVersion, RequiresManagerApproval, AuthenticationEnabled, EnrolleeSuppliesSubject, CertificateApplicationPolicy, CertificateNameFlag, EffectiveEKUs, EnrollmentFlag, NoSecurityExtension, RenewalPeriod, ValidityPeriod, OID} + return []Property{AdminCount, CASecurityCollected, CAName, CertChain, CertName, CertThumbprint, CertThumbprints, HasEnrollmentAgentRestrictions, EnrollmentAgentRestrictionsCollected, IsUserSpecifiesSanEnabled, IsUserSpecifiesSanEnabledCollected, HasBasicConstraints, BasicConstraintPathLength, DNSHostname, CrossCertificatePair, DistinguishedName, DomainFQDN, DomainSID, Sensitive, HighValue, BlocksInheritance, IsACL, IsACLProtected, IsDeleted, Enforced, Department, HasCrossCertificatePair, HasSPN, UnconstrainedDelegation, LastLogon, LastLogonTimestamp, IsPrimaryGroup, HasLAPS, DontRequirePreAuth, LogonType, HasURA, PasswordNeverExpires, PasswordNotRequired, FunctionalLevel, TrustType, SidFiltering, TrustedToAuth, SamAccountName, CertificateMappingMethodsRaw, CertificateMappingMethods, StrongCertificateBindingEnforcementRaw, StrongCertificateBindingEnforcement, EKUs, SubjectAltRequireUPN, AuthorizedSignatures, ApplicationPolicies, SchemaVersion, RequiresManagerApproval, AuthenticationEnabled, EnrolleeSuppliesSubject, CertificateApplicationPolicy, CertificateNameFlag, EffectiveEKUs, EnrollmentFlag, NoSecurityExtension, RenewalPeriod, ValidityPeriod, OID} } func ParseProperty(source string) (Property, error) { switch source { @@ -185,8 +187,12 @@ func ParseProperty(source string) (Property, error) { return CertThumbprint, nil case "certthumbprints": return CertThumbprints, nil + case "hasenrollmentagentrestrictions": + return HasEnrollmentAgentRestrictions, nil case "enrollmentagentrestrictionscollected": return EnrollmentAgentRestrictionsCollected, nil + case "isuserspecifiessanenabled": + return IsUserSpecifiesSanEnabled, nil case "isuserspecifiessanenabledcollected": return IsUserSpecifiesSanEnabledCollected, nil case "hasbasicconstraints": @@ -313,8 +319,12 @@ func (s Property) String() string { return string(CertThumbprint) case CertThumbprints: return string(CertThumbprints) + case HasEnrollmentAgentRestrictions: + return string(HasEnrollmentAgentRestrictions) case EnrollmentAgentRestrictionsCollected: return string(EnrollmentAgentRestrictionsCollected) + case IsUserSpecifiesSanEnabled: + return string(IsUserSpecifiesSanEnabled) case IsUserSpecifiesSanEnabledCollected: return string(IsUserSpecifiesSanEnabledCollected) case HasBasicConstraints: @@ -441,8 +451,12 @@ func (s Property) Name() string { return "Certificate Thumbprint" case CertThumbprints: return "Certificate Thumbprints" + case HasEnrollmentAgentRestrictions: + return "Has Enrollment Agent Restrictions" case EnrollmentAgentRestrictionsCollected: return "Enrollment Agent Restrictions Collected" + case IsUserSpecifiesSanEnabled: + return "Is User Specifies San Enabled" case IsUserSpecifiesSanEnabledCollected: return "Is User Specifies San Enabled Collected" case HasBasicConstraints: diff --git a/packages/javascript/bh-shared-ui/src/graphSchema.ts b/packages/javascript/bh-shared-ui/src/graphSchema.ts index f9cb0be3c..f67bfa473 100644 --- a/packages/javascript/bh-shared-ui/src/graphSchema.ts +++ b/packages/javascript/bh-shared-ui/src/graphSchema.ts @@ -258,7 +258,9 @@ export enum ActiveDirectoryKindProperties { CertName = 'certname', CertThumbprint = 'certthumbprint', CertThumbprints = 'certthumbprints', + HasEnrollmentAgentRestrictions = 'hasenrollmentagentrestrictions', EnrollmentAgentRestrictionsCollected = 'enrollmentagentrestrictionscollected', + IsUserSpecifiesSanEnabled = 'isuserspecifiessanenabled', IsUserSpecifiesSanEnabledCollected = 'isuserspecifiessanenabledcollected', HasBasicConstraints = 'hasbasicconstraints', BasicConstraintPathLength = 'basicconstraintpathlength', @@ -329,8 +331,12 @@ export function ActiveDirectoryKindPropertiesToDisplay(value: ActiveDirectoryKin return 'Certificate Thumbprint'; case ActiveDirectoryKindProperties.CertThumbprints: return 'Certificate Thumbprints'; + case ActiveDirectoryKindProperties.HasEnrollmentAgentRestrictions: + return 'Has Enrollment Agent Restrictions'; case ActiveDirectoryKindProperties.EnrollmentAgentRestrictionsCollected: return 'Enrollment Agent Restrictions Collected'; + case ActiveDirectoryKindProperties.IsUserSpecifiesSanEnabled: + return 'Is User Specifies San Enabled'; case ActiveDirectoryKindProperties.IsUserSpecifiesSanEnabledCollected: return 'Is User Specifies San Enabled Collected'; case ActiveDirectoryKindProperties.HasBasicConstraints: From 4bd8319d2656b1bdaee23b18ad8dfbd6ccba2684 Mon Sep 17 00:00:00 2001 From: Ulises Rangel Date: Wed, 15 Nov 2023 10:06:25 -0600 Subject: [PATCH 3/4] chore: move post local groups to bhce packages for use in BHE, run license generation for headers (#209) --- cmd/api/src/analysis/ad/post.go | 122 +------------------------ packages/go/analysis/ad/post.go | 117 ++++++++++++++++++++++++ packages/go/dawgs/graph/mocks/graph.go | 15 +++ 3 files changed, 133 insertions(+), 121 deletions(-) diff --git a/cmd/api/src/analysis/ad/post.go b/cmd/api/src/analysis/ad/post.go index 82125b75b..668e3594b 100644 --- a/cmd/api/src/analysis/ad/post.go +++ b/cmd/api/src/analysis/ad/post.go @@ -18,133 +18,13 @@ package ad import ( "context" - "fmt" "github.com/specterops/bloodhound/analysis" adAnalysis "github.com/specterops/bloodhound/analysis/ad" - "github.com/specterops/bloodhound/analysis/impact" "github.com/specterops/bloodhound/dawgs/graph" - "github.com/specterops/bloodhound/dawgs/util/channels" "github.com/specterops/bloodhound/graphschema/ad" - "github.com/specterops/bloodhound/log" ) -func PostLocalGroups(ctx context.Context, db graph.Database, localGroupExpansions impact.PathAggregator) (*analysis.AtomicPostProcessingStats, error) { - var ( - adminGroupSuffix = "-544" - psRemoteGroupSuffix = "-580" - dcomGroupSuffix = "-562" - ) - - if computers, err := adAnalysis.FetchComputers(ctx, db); err != nil { - return &analysis.AtomicPostProcessingStats{}, err - } else { - var ( - threadSafeLocalGroupExpansions = impact.NewThreadSafeAggregator(localGroupExpansions) - operation = analysis.NewPostRelationshipOperation(ctx, db, "LocalGroup Post Processing") - ) - - for idx, computer := range computers.ToArray() { - computerID := graph.ID(computer) - - if idx > 0 && idx%10000 == 0 { - log.Infof("Post processed %d active directory computers", idx) - } - - if err := operation.Operation.SubmitReader(func(ctx context.Context, tx graph.Transaction, outC chan<- analysis.CreatePostRelationshipJob) error { - if entities, err := adAnalysis.FetchLocalGroupBitmapForComputer(tx, computerID, dcomGroupSuffix); err != nil { - return err - } else { - for _, admin := range entities.Slice() { - nextJob := analysis.CreatePostRelationshipJob{ - FromID: graph.ID(admin), - ToID: computerID, - Kind: ad.ExecuteDCOM, - } - - if !channels.Submit(ctx, outC, nextJob) { - return nil - } - } - - return nil - } - }); err != nil { - return &analysis.AtomicPostProcessingStats{}, fmt.Errorf("failed submitting reader for operation involving computer %d: %w", computerID, err) - } - - if err := operation.Operation.SubmitReader(func(ctx context.Context, tx graph.Transaction, outC chan<- analysis.CreatePostRelationshipJob) error { - if entities, err := adAnalysis.FetchLocalGroupBitmapForComputer(tx, computerID, psRemoteGroupSuffix); err != nil { - return err - } else { - for _, admin := range entities.Slice() { - nextJob := analysis.CreatePostRelationshipJob{ - FromID: graph.ID(admin), - ToID: computerID, - Kind: ad.CanPSRemote, - } - - if !channels.Submit(ctx, outC, nextJob) { - return nil - } - } - - return nil - } - }); err != nil { - return &analysis.AtomicPostProcessingStats{}, fmt.Errorf("failed submitting reader for operation involving computer %d: %w", computerID, err) - } - - if err := operation.Operation.SubmitReader(func(ctx context.Context, tx graph.Transaction, outC chan<- analysis.CreatePostRelationshipJob) error { - if entities, err := adAnalysis.FetchLocalGroupBitmapForComputer(tx, computerID, adminGroupSuffix); err != nil { - return err - } else { - for _, admin := range entities.Slice() { - nextJob := analysis.CreatePostRelationshipJob{ - FromID: graph.ID(admin), - ToID: computerID, - Kind: ad.AdminTo, - } - - if !channels.Submit(ctx, outC, nextJob) { - return nil - } - } - - return nil - } - }); err != nil { - return &analysis.AtomicPostProcessingStats{}, fmt.Errorf("failed submitting reader for operation involving computer %d: %w", computerID, err) - } - - if err := operation.Operation.SubmitReader(func(ctx context.Context, tx graph.Transaction, outC chan<- analysis.CreatePostRelationshipJob) error { - if entities, err := adAnalysis.FetchRDPEntityBitmapForComputerWithUnenforcedURA(tx, computerID, threadSafeLocalGroupExpansions); err != nil { - return err - } else { - for _, rdp := range entities.Slice() { - nextJob := analysis.CreatePostRelationshipJob{ - FromID: graph.ID(rdp), - ToID: computerID, - Kind: ad.CanRDP, - } - - if !channels.Submit(ctx, outC, nextJob) { - return nil - } - } - } - - return nil - }); err != nil { - return &analysis.AtomicPostProcessingStats{}, fmt.Errorf("failed submitting reader for operation involving computer %d: %w", computerID, err) - } - } - - log.Infof("Finished post-processing %d active directory computers", computers.GetCardinality()) - return &operation.Stats, operation.Done() - } -} - func Post(ctx context.Context, db graph.Database) (*analysis.AtomicPostProcessingStats, error) { aggregateStats := analysis.NewAtomicPostProcessingStats() if stats, err := analysis.DeleteTransitEdges(ctx, db, ad.Entity, ad.Entity, adAnalysis.PostProcessedRelationships()...); err != nil { @@ -155,7 +35,7 @@ func Post(ctx context.Context, db graph.Database) (*analysis.AtomicPostProcessin return &aggregateStats, err } else if groupExpansions, err := adAnalysis.ExpandAllRDPLocalGroups(ctx, db); err != nil { return &aggregateStats, err - } else if localGroupStats, err := PostLocalGroups(ctx, db, groupExpansions); err != nil { + } else if localGroupStats, err := adAnalysis.PostLocalGroups(ctx, db, groupExpansions); err != nil { return &aggregateStats, err } else if adcsStats, err := adAnalysis.PostADCS(ctx, db, groupExpansions); err != nil { return &aggregateStats, err diff --git a/packages/go/analysis/ad/post.go b/packages/go/analysis/ad/post.go index a24546ac5..203d42f59 100644 --- a/packages/go/analysis/ad/post.go +++ b/packages/go/analysis/ad/post.go @@ -18,6 +18,7 @@ package ad import ( "context" + "fmt" "github.com/RoaringBitmap/roaring/roaring64" "github.com/specterops/bloodhound/analysis" @@ -190,6 +191,122 @@ func getLAPSComputersForDomain(tx graph.Transaction, domain *graph.Node) ([]grap } } +func PostLocalGroups(ctx context.Context, db graph.Database, localGroupExpansions impact.PathAggregator) (*analysis.AtomicPostProcessingStats, error) { + var ( + adminGroupSuffix = "-544" + psRemoteGroupSuffix = "-580" + dcomGroupSuffix = "-562" + ) + + if computers, err := FetchComputers(ctx, db); err != nil { + return &analysis.AtomicPostProcessingStats{}, err + } else { + var ( + threadSafeLocalGroupExpansions = impact.NewThreadSafeAggregator(localGroupExpansions) + operation = analysis.NewPostRelationshipOperation(ctx, db, "LocalGroup Post Processing") + ) + + for idx, computer := range computers.ToArray() { + computerID := graph.ID(computer) + + if idx > 0 && idx%10000 == 0 { + log.Infof("Post processed %d active directory computers", idx) + } + + if err := operation.Operation.SubmitReader(func(ctx context.Context, tx graph.Transaction, outC chan<- analysis.CreatePostRelationshipJob) error { + if entities, err := FetchLocalGroupBitmapForComputer(tx, computerID, dcomGroupSuffix); err != nil { + return err + } else { + for _, admin := range entities.Slice() { + nextJob := analysis.CreatePostRelationshipJob{ + FromID: graph.ID(admin), + ToID: computerID, + Kind: ad.ExecuteDCOM, + } + + if !channels.Submit(ctx, outC, nextJob) { + return nil + } + } + + return nil + } + }); err != nil { + return &analysis.AtomicPostProcessingStats{}, fmt.Errorf("failed submitting reader for operation involving computer %d: %w", computerID, err) + } + + if err := operation.Operation.SubmitReader(func(ctx context.Context, tx graph.Transaction, outC chan<- analysis.CreatePostRelationshipJob) error { + if entities, err := FetchLocalGroupBitmapForComputer(tx, computerID, psRemoteGroupSuffix); err != nil { + return err + } else { + for _, admin := range entities.Slice() { + nextJob := analysis.CreatePostRelationshipJob{ + FromID: graph.ID(admin), + ToID: computerID, + Kind: ad.CanPSRemote, + } + + if !channels.Submit(ctx, outC, nextJob) { + return nil + } + } + + return nil + } + }); err != nil { + return &analysis.AtomicPostProcessingStats{}, fmt.Errorf("failed submitting reader for operation involving computer %d: %w", computerID, err) + } + + if err := operation.Operation.SubmitReader(func(ctx context.Context, tx graph.Transaction, outC chan<- analysis.CreatePostRelationshipJob) error { + if entities, err := FetchLocalGroupBitmapForComputer(tx, computerID, adminGroupSuffix); err != nil { + return err + } else { + for _, admin := range entities.Slice() { + nextJob := analysis.CreatePostRelationshipJob{ + FromID: graph.ID(admin), + ToID: computerID, + Kind: ad.AdminTo, + } + + if !channels.Submit(ctx, outC, nextJob) { + return nil + } + } + + return nil + } + }); err != nil { + return &analysis.AtomicPostProcessingStats{}, fmt.Errorf("failed submitting reader for operation involving computer %d: %w", computerID, err) + } + + if err := operation.Operation.SubmitReader(func(ctx context.Context, tx graph.Transaction, outC chan<- analysis.CreatePostRelationshipJob) error { + if entities, err := FetchRDPEntityBitmapForComputerWithUnenforcedURA(tx, computerID, threadSafeLocalGroupExpansions); err != nil { + return err + } else { + for _, rdp := range entities.Slice() { + nextJob := analysis.CreatePostRelationshipJob{ + FromID: graph.ID(rdp), + ToID: computerID, + Kind: ad.CanRDP, + } + + if !channels.Submit(ctx, outC, nextJob) { + return nil + } + } + } + + return nil + }); err != nil { + return &analysis.AtomicPostProcessingStats{}, fmt.Errorf("failed submitting reader for operation involving computer %d: %w", computerID, err) + } + } + + log.Infof("Finished post-processing %d active directory computers", computers.GetCardinality()) + return &operation.Stats, operation.Done() + } +} + func ExpandLocalGroupMembership(tx graph.Transaction, candidates graph.NodeSet) (graph.NodeSet, error) { if paths, err := ExpandLocalGroupMembershipPaths(tx, candidates); err != nil { return nil, err diff --git a/packages/go/dawgs/graph/mocks/graph.go b/packages/go/dawgs/graph/mocks/graph.go index f2bc543de..0dfb17b39 100644 --- a/packages/go/dawgs/graph/mocks/graph.go +++ b/packages/go/dawgs/graph/mocks/graph.go @@ -186,6 +186,21 @@ func (mr *MockPropertyValueMockRecorder) String() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "String", reflect.TypeOf((*MockPropertyValue)(nil).String)) } +// StringSlice mocks base method. +func (m *MockPropertyValue) StringSlice() ([]string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StringSlice") + ret0, _ := ret[0].([]string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// StringSlice indicates an expected call of StringSlice. +func (mr *MockPropertyValueMockRecorder) StringSlice() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StringSlice", reflect.TypeOf((*MockPropertyValue)(nil).StringSlice)) +} + // Time mocks base method. func (m *MockPropertyValue) Time() (time.Time, error) { m.ctrl.T.Helper() From a57f1302b720f2366b1ccd4699faefa3a960a064 Mon Sep 17 00:00:00 2001 From: slokie-so <140854032+slokie-so@users.noreply.github.com> Date: Wed, 15 Nov 2023 11:57:07 -0500 Subject: [PATCH 4/4] Update jira-issue-transfer.yml (#214) * Update jira-issue-transfer.yml Corrected Runs-On * Update jira-issue-transfer.yml --- .github/workflows/jira-issue-transfer.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/jira-issue-transfer.yml b/.github/workflows/jira-issue-transfer.yml index aa8438f77..36746a2e5 100644 --- a/.github/workflows/jira-issue-transfer.yml +++ b/.github/workflows/jira-issue-transfer.yml @@ -16,8 +16,6 @@ name: Jira Issue Transfer -runs-on: self-hosted - on: issues: types: @@ -25,7 +23,7 @@ on: jobs: build: - runs-on: ubuntu-latest + runs-on: self-hosted steps: - name: Login uses: atlassian/gajira-login@v3