diff --git a/cmd/api/src/analysis/ad/adcs_integration_test.go b/cmd/api/src/analysis/ad/adcs_integration_test.go index 39e9bd9213..5a85fe3ed2 100644 --- a/cmd/api/src/analysis/ad/adcs_integration_test.go +++ b/cmd/api/src/analysis/ad/adcs_integration_test.go @@ -447,63 +447,75 @@ func TestTrustedForNTAuth(t *testing.T) { func TestEnrollOnBehalfOf(t *testing.T) { testContext := integration.NewGraphTestContext(t, graphschema.DefaultGraphSchema()) testContext.DatabaseTestWithSetup(func(harness *integration.HarnessDetails) error { - harness.EnrollOnBehalfOfHarnessOne.Setup(testContext) + harness.EnrollOnBehalfOfHarness1.Setup(testContext) return nil }, func(harness integration.HarnessDetails, db graph.Database) { certTemplates, err := ad2.FetchNodesByKind(context.Background(), db, ad.CertTemplate) v1Templates := make([]*graph.Node, 0) + v2Templates := make([]*graph.Node, 0) + for _, template := range certTemplates { if version, err := template.Properties.Get(ad.SchemaVersion.String()).Float64(); err != nil { continue } else if version == 1 { v1Templates = append(v1Templates, template) } else if version >= 2 { - continue + v2Templates = append(v2Templates, template) } } require.Nil(t, err) db.ReadTransaction(context.Background(), func(tx graph.Transaction) error { - results, err := ad2.EnrollOnBehalfOfVersionOne(tx, v1Templates, certTemplates) + results, err := ad2.EnrollOnBehalfOfVersionOne(tx, v1Templates, certTemplates, harness.EnrollOnBehalfOfHarness1.Domain1) require.Nil(t, err) require.Len(t, results, 3) require.Contains(t, results, analysis.CreatePostRelationshipJob{ - FromID: harness.EnrollOnBehalfOfHarnessOne.CertTemplate11.ID, - ToID: harness.EnrollOnBehalfOfHarnessOne.CertTemplate12.ID, + FromID: harness.EnrollOnBehalfOfHarness1.CertTemplate11.ID, + ToID: harness.EnrollOnBehalfOfHarness1.CertTemplate12.ID, Kind: ad.EnrollOnBehalfOf, }) require.Contains(t, results, analysis.CreatePostRelationshipJob{ - FromID: harness.EnrollOnBehalfOfHarnessOne.CertTemplate13.ID, - ToID: harness.EnrollOnBehalfOfHarnessOne.CertTemplate12.ID, + FromID: harness.EnrollOnBehalfOfHarness1.CertTemplate13.ID, + ToID: harness.EnrollOnBehalfOfHarness1.CertTemplate12.ID, Kind: ad.EnrollOnBehalfOf, }) require.Contains(t, results, analysis.CreatePostRelationshipJob{ - FromID: harness.EnrollOnBehalfOfHarnessOne.CertTemplate12.ID, - ToID: harness.EnrollOnBehalfOfHarnessOne.CertTemplate12.ID, + FromID: harness.EnrollOnBehalfOfHarness1.CertTemplate12.ID, + ToID: harness.EnrollOnBehalfOfHarness1.CertTemplate12.ID, Kind: ad.EnrollOnBehalfOf, }) return nil }) + + db.ReadTransaction(context.Background(), func(tx graph.Transaction) error { + results, err := ad2.EnrollOnBehalfOfVersionTwo(tx, v2Templates, certTemplates, harness.EnrollOnBehalfOfHarness1.Domain1) + require.Nil(t, err) + + require.Len(t, results, 0) + + return nil + }) }) testContext.DatabaseTestWithSetup(func(harness *integration.HarnessDetails) error { - harness.EnrollOnBehalfOfHarnessTwo.Setup(testContext) + harness.EnrollOnBehalfOfHarness2.Setup(testContext) return nil }, func(harness integration.HarnessDetails, db graph.Database) { certTemplates, err := ad2.FetchNodesByKind(context.Background(), db, ad.CertTemplate) + v1Templates := make([]*graph.Node, 0) v2Templates := make([]*graph.Node, 0) for _, template := range certTemplates { if version, err := template.Properties.Get(ad.SchemaVersion.String()).Float64(); err != nil { continue } else if version == 1 { - continue + v1Templates = append(v1Templates, template) } else if version >= 2 { v2Templates = append(v2Templates, template) } @@ -512,15 +524,60 @@ func TestEnrollOnBehalfOf(t *testing.T) { require.Nil(t, err) db.ReadTransaction(context.Background(), func(tx graph.Transaction) error { - results, err := ad2.EnrollOnBehalfOfVersionTwo(tx, v2Templates, certTemplates) + results, err := ad2.EnrollOnBehalfOfVersionOne(tx, v1Templates, certTemplates, harness.EnrollOnBehalfOfHarness2.Domain2) + require.Nil(t, err) + + require.Len(t, results, 0) + return nil + }) + + db.ReadTransaction(context.Background(), func(tx graph.Transaction) error { + results, err := ad2.EnrollOnBehalfOfVersionTwo(tx, v2Templates, certTemplates, harness.EnrollOnBehalfOfHarness2.Domain2) require.Nil(t, err) require.Len(t, results, 1) require.Contains(t, results, analysis.CreatePostRelationshipJob{ - FromID: harness.EnrollOnBehalfOfHarnessTwo.CertTemplate21.ID, - ToID: harness.EnrollOnBehalfOfHarnessTwo.CertTemplate23.ID, + FromID: harness.EnrollOnBehalfOfHarness2.CertTemplate21.ID, + ToID: harness.EnrollOnBehalfOfHarness2.CertTemplate23.ID, Kind: ad.EnrollOnBehalfOf, }) + return nil + }) + }) + + testContext.DatabaseTestWithSetup(func(harness *integration.HarnessDetails) error { + harness.EnrollOnBehalfOfHarness3.Setup(testContext) + return nil + }, func(harness integration.HarnessDetails, db graph.Database) { + operation := analysis.NewPostRelationshipOperation(context.Background(), db, "ADCS Post Process Test - EnrollOnBehalfOf 3") + + _, enterpriseCertAuthorities, certTemplates, domains, cache, err := FetchADCSPrereqs(db) + require.Nil(t, err) + + if err := ad2.PostEnrollOnBehalfOf(domains, enterpriseCertAuthorities, certTemplates, cache, operation); err != nil { + t.Logf("failed post processing for %s: %v", ad.EnrollOnBehalfOf.String(), err) + } + err = operation.Done() + require.Nil(t, err) + + db.ReadTransaction(context.Background(), func(tx graph.Transaction) error { + if startNodes, err := ops.FetchStartNodes(tx.Relationships().Filterf(func() graph.Criteria { + return query.Kind(query.Relationship(), ad.EnrollOnBehalfOf) + })); err != nil { + t.Fatalf("error fetching EnrollOnBehalfOf edges in integration test; %v", err) + } else if endNodes, err := ops.FetchStartNodes(tx.Relationships().Filterf(func() graph.Criteria { + return query.Kind(query.Relationship(), ad.EnrollOnBehalfOf) + })); err != nil { + t.Fatalf("error fetching EnrollOnBehalfOf edges in integration test; %v", err) + } else { + require.Len(t, startNodes, 2) + require.True(t, startNodes.Contains(harness.EnrollOnBehalfOfHarness3.CertTemplate11)) + require.True(t, startNodes.Contains(harness.EnrollOnBehalfOfHarness3.CertTemplate12)) + + require.Len(t, endNodes, 2) + require.True(t, startNodes.Contains(harness.EnrollOnBehalfOfHarness3.CertTemplate12)) + require.True(t, startNodes.Contains(harness.EnrollOnBehalfOfHarness3.CertTemplate12)) + } return nil }) diff --git a/cmd/api/src/test/integration/harnesses.go b/cmd/api/src/test/integration/harnesses.go index 637aebc7c0..dede7f384a 100644 --- a/cmd/api/src/test/integration/harnesses.go +++ b/cmd/api/src/test/integration/harnesses.go @@ -1595,7 +1595,7 @@ func (s *ADCSESC1HarnessAuthUsers) Setup(graphTestContext *GraphTestContext) { graphTestContext.UpdateNode(s.AuthUsers) } -type EnrollOnBehalfOfHarnessTwo struct { +type EnrollOnBehalfOfHarness2 struct { Domain2 *graph.Node AuthStore2 *graph.Node RootCA2 *graph.Node @@ -1604,10 +1604,9 @@ type EnrollOnBehalfOfHarnessTwo struct { CertTemplate22 *graph.Node CertTemplate23 *graph.Node CertTemplate24 *graph.Node - CertTemplate25 *graph.Node } -func (s *EnrollOnBehalfOfHarnessTwo) Setup(gt *GraphTestContext) { +func (s *EnrollOnBehalfOfHarness2) Setup(gt *GraphTestContext) { certRequestAgentEKU := make([]string, 0) certRequestAgentEKU = append(certRequestAgentEKU, adAnalysis.EkuCertRequestAgent) emptyAppPolicies := make([]string, 0) @@ -1623,7 +1622,7 @@ func (s *EnrollOnBehalfOfHarnessTwo) Setup(gt *GraphTestContext) { SubjectAltRequireUPN: false, SubjectAltRequireSPN: false, NoSecurityExtension: false, - SchemaVersion: 1, + SchemaVersion: 2, AuthorizedSignatures: 0, EffectiveEKUs: certRequestAgentEKU, ApplicationPolicies: emptyAppPolicies, @@ -1635,7 +1634,7 @@ func (s *EnrollOnBehalfOfHarnessTwo) Setup(gt *GraphTestContext) { SubjectAltRequireUPN: false, SubjectAltRequireSPN: false, NoSecurityExtension: false, - SchemaVersion: 1, + SchemaVersion: 2, AuthorizedSignatures: 0, EffectiveEKUs: []string{adAnalysis.EkuCertRequestAgent, adAnalysis.EkuAnyPurpose}, ApplicationPolicies: emptyAppPolicies, @@ -1664,18 +1663,6 @@ func (s *EnrollOnBehalfOfHarnessTwo) Setup(gt *GraphTestContext) { EffectiveEKUs: emptyAppPolicies, ApplicationPolicies: emptyAppPolicies, }) - s.CertTemplate25 = gt.NewActiveDirectoryCertTemplate("certtemplate2-5", sid, CertTemplateData{ - RequiresManagerApproval: false, - AuthenticationEnabled: false, - EnrolleeSuppliesSubject: false, - SubjectAltRequireUPN: false, - SubjectAltRequireSPN: false, - NoSecurityExtension: false, - SchemaVersion: 1, - AuthorizedSignatures: 1, - EffectiveEKUs: emptyAppPolicies, - ApplicationPolicies: emptyAppPolicies, - }) gt.NewRelationship(s.AuthStore2, s.Domain2, ad.NTAuthStoreFor) gt.NewRelationship(s.RootCA2, s.Domain2, ad.RootCAFor) @@ -1685,10 +1672,9 @@ func (s *EnrollOnBehalfOfHarnessTwo) Setup(gt *GraphTestContext) { gt.NewRelationship(s.CertTemplate22, s.EnterpriseCA2, ad.PublishedTo) gt.NewRelationship(s.CertTemplate23, s.EnterpriseCA2, ad.PublishedTo) gt.NewRelationship(s.CertTemplate24, s.EnterpriseCA2, ad.PublishedTo) - gt.NewRelationship(s.CertTemplate25, s.EnterpriseCA2, ad.PublishedTo) } -type EnrollOnBehalfOfHarnessOne struct { +type EnrollOnBehalfOfHarness1 struct { Domain1 *graph.Node AuthStore1 *graph.Node RootCA1 *graph.Node @@ -1698,7 +1684,7 @@ type EnrollOnBehalfOfHarnessOne struct { CertTemplate13 *graph.Node } -func (s *EnrollOnBehalfOfHarnessOne) Setup(gt *GraphTestContext) { +func (s *EnrollOnBehalfOfHarness1) Setup(gt *GraphTestContext) { sid := RandomDomainSID() anyPurposeEkus := make([]string, 0) anyPurposeEkus = append(anyPurposeEkus, adAnalysis.EkuAnyPurpose) @@ -1753,6 +1739,74 @@ func (s *EnrollOnBehalfOfHarnessOne) Setup(gt *GraphTestContext) { gt.NewRelationship(s.CertTemplate13, s.EnterpriseCA1, ad.PublishedTo) } +type EnrollOnBehalfOfHarness3 struct { + Domain1 *graph.Node + AuthStore1 *graph.Node + RootCA1 *graph.Node + EnterpriseCA1 *graph.Node + EnterpriseCA2 *graph.Node + CertTemplate11 *graph.Node + CertTemplate12 *graph.Node + CertTemplate13 *graph.Node +} + +func (s *EnrollOnBehalfOfHarness3) Setup(gt *GraphTestContext) { + sid := RandomDomainSID() + anyPurposeEkus := make([]string, 0) + anyPurposeEkus = append(anyPurposeEkus, adAnalysis.EkuAnyPurpose) + emptyAppPolicies := make([]string, 0) + s.Domain1 = gt.NewActiveDirectoryDomain("domain1", sid, false, true) + s.AuthStore1 = gt.NewActiveDirectoryNTAuthStore("authstore1", sid) + s.RootCA1 = gt.NewActiveDirectoryRootCA("rca1", sid) + s.EnterpriseCA1 = gt.NewActiveDirectoryEnterpriseCA("eca1", sid) + s.EnterpriseCA2 = gt.NewActiveDirectoryEnterpriseCA("eca2", sid) + s.CertTemplate11 = gt.NewActiveDirectoryCertTemplate("certtemplate1-1", sid, CertTemplateData{ + RequiresManagerApproval: false, + AuthenticationEnabled: false, + EnrolleeSuppliesSubject: false, + SubjectAltRequireUPN: false, + SubjectAltRequireSPN: false, + NoSecurityExtension: false, + SchemaVersion: 2, + AuthorizedSignatures: 0, + EffectiveEKUs: anyPurposeEkus, + ApplicationPolicies: emptyAppPolicies, + }) + s.CertTemplate12 = gt.NewActiveDirectoryCertTemplate("certtemplate1-2", sid, CertTemplateData{ + RequiresManagerApproval: false, + AuthenticationEnabled: false, + EnrolleeSuppliesSubject: false, + SubjectAltRequireUPN: false, + SubjectAltRequireSPN: false, + NoSecurityExtension: false, + SchemaVersion: 1, + AuthorizedSignatures: 0, + EffectiveEKUs: anyPurposeEkus, + ApplicationPolicies: emptyAppPolicies, + }) + s.CertTemplate13 = gt.NewActiveDirectoryCertTemplate("certtemplate1-3", sid, CertTemplateData{ + RequiresManagerApproval: false, + AuthenticationEnabled: false, + EnrolleeSuppliesSubject: false, + SubjectAltRequireUPN: false, + SubjectAltRequireSPN: false, + NoSecurityExtension: false, + SchemaVersion: 2, + AuthorizedSignatures: 0, + EffectiveEKUs: anyPurposeEkus, + ApplicationPolicies: emptyAppPolicies, + }) + + gt.NewRelationship(s.AuthStore1, s.Domain1, ad.NTAuthStoreFor) + gt.NewRelationship(s.RootCA1, s.Domain1, ad.RootCAFor) + gt.NewRelationship(s.EnterpriseCA1, s.AuthStore1, ad.TrustedForNTAuth) + gt.NewRelationship(s.EnterpriseCA1, s.RootCA1, ad.EnterpriseCAFor) + gt.NewRelationship(s.EnterpriseCA2, s.RootCA1, ad.EnterpriseCAFor) + gt.NewRelationship(s.CertTemplate11, s.EnterpriseCA1, ad.PublishedTo) + gt.NewRelationship(s.CertTemplate12, s.EnterpriseCA1, ad.PublishedTo) + gt.NewRelationship(s.CertTemplate13, s.EnterpriseCA2, ad.PublishedTo) +} + type ADCSGoldenCertHarness struct { NTAuthStore1 *graph.Node RootCA1 *graph.Node @@ -8437,8 +8491,9 @@ type HarnessDetails struct { ShortcutHarnessEveryone2 ShortcutHarnessEveryone2 ADCSESC1Harness ADCSESC1Harness ADCSESC1HarnessAuthUsers ADCSESC1HarnessAuthUsers - EnrollOnBehalfOfHarnessOne EnrollOnBehalfOfHarnessOne - EnrollOnBehalfOfHarnessTwo EnrollOnBehalfOfHarnessTwo + EnrollOnBehalfOfHarness1 EnrollOnBehalfOfHarness1 + EnrollOnBehalfOfHarness2 EnrollOnBehalfOfHarness2 + EnrollOnBehalfOfHarness3 EnrollOnBehalfOfHarness3 ADCSGoldenCertHarness ADCSGoldenCertHarness IssuedSignedByHarness IssuedSignedByHarness EnterpriseCAForHarness EnterpriseCAForHarness diff --git a/cmd/api/src/test/integration/harnesses/enrollonbehalfof-1.json b/cmd/api/src/test/integration/harnesses/enrollonbehalfof-1.json index cc51045b70..9232e6f121 100644 --- a/cmd/api/src/test/integration/harnesses/enrollonbehalfof-1.json +++ b/cmd/api/src/test/integration/harnesses/enrollonbehalfof-1.json @@ -54,10 +54,10 @@ }, "nodes": [ { - "id": "n1", + "id": "n0", "position": { - "x": 729.9551990267428, - "y": -4 + "x": 675.9551990267428, + "y": 50 }, "caption": "Domain1", "labels": [], @@ -67,10 +67,10 @@ } }, { - "id": "n2", + "id": "n1", "position": { - "x": 129, - "y": 273.97628342478527 + "x": 75, + "y": 327.97628342478527 }, "caption": "CertTemplate1-1", "labels": [], @@ -83,10 +83,10 @@ } }, { - "id": "n3", + "id": "n2", "position": { - "x": 487.6313891898351, - "y": -4 + "x": 433.6313891898351, + "y": 50 }, "caption": "NTAuthStore1", "labels": [], @@ -96,10 +96,10 @@ } }, { - "id": "n4", + "id": "n3", "position": { - "x": 487.6313891898351, - "y": 273.97628342478527 + "x": 433.6313891898351, + "y": 327.97628342478527 }, "caption": "EnterpriseCA1", "labels": [], @@ -109,10 +109,10 @@ } }, { - "id": "n5", + "id": "n4", "position": { - "x": 230.03558347937087, - "y": 551.9525668495705 + "x": 176.03558347937087, + "y": 605.9525668495705 }, "caption": "CertTemplate1-2", "labels": [], @@ -125,10 +125,10 @@ } }, { - "id": "n6", + "id": "n5", "position": { - "x": 508.01086036954564, - "y": 551.2045130499298 + "x": 454.01086036954564, + "y": 605.2045130499298 }, "caption": "CertTemplate1-3", "labels": [], @@ -141,10 +141,10 @@ } }, { - "id": "n7", + "id": "n6", "position": { - "x": 729.9551990267428, - "y": 273.97628342478527 + "x": 675.9551990267428, + "y": 327.97628342478527 }, "caption": "RootCA1", "labels": [], @@ -157,64 +157,64 @@ "relationships": [ { "id": "n0", - "fromId": "n3", - "toId": "n1", + "fromId": "n2", + "toId": "n0", "type": "NTAuthStoreFor", "properties": {}, "style": {} }, { "id": "n1", - "fromId": "n4", - "toId": "n3", + "fromId": "n3", + "toId": "n2", "type": "TrustedForNTAuth", "properties": {}, "style": {} }, { "id": "n2", - "fromId": "n2", - "toId": "n4", + "fromId": "n1", + "toId": "n3", "type": "PublishedTo", "properties": {}, "style": {} }, { "id": "n3", - "fromId": "n5", - "toId": "n4", + "fromId": "n4", + "toId": "n3", "type": "PublishedTo", "properties": {}, "style": {} }, { "id": "n4", - "fromId": "n6", - "toId": "n4", + "fromId": "n5", + "toId": "n3", "type": "PublishedTo", "properties": {}, "style": {} }, { "id": "n5", - "fromId": "n7", - "toId": "n1", + "fromId": "n6", + "toId": "n0", "type": "RootCAFor", "properties": {}, "style": {} }, { "id": "n6", - "fromId": "n4", - "toId": "n7", + "fromId": "n3", + "toId": "n6", "type": "EnterpriseCAFor", "properties": {}, "style": {} }, { "id": "n7", - "fromId": "n2", - "toId": "n5", + "fromId": "n1", + "toId": "n4", "type": "EnrollOnBehalfOf", "properties": {}, "style": { @@ -223,13 +223,23 @@ }, { "id": "n8", - "fromId": "n6", - "toId": "n5", + "fromId": "n5", + "toId": "n4", "type": "EnrollOnBehalfOf", "properties": {}, "style": { "arrow-color": "#68ccca" } + }, + { + "id": "n9", + "type": "EnrollOnBehalfOf", + "style": { + "arrow-color": "#68ccca" + }, + "properties": {}, + "fromId": "n4", + "toId": "n4" } ] } \ No newline at end of file diff --git a/cmd/api/src/test/integration/harnesses/enrollonbehalfof-1.svg b/cmd/api/src/test/integration/harnesses/enrollonbehalfof-1.svg index a86d80d2f0..6fcfa6838d 100644 --- a/cmd/api/src/test/integration/harnesses/enrollonbehalfof-1.svg +++ b/cmd/api/src/test/integration/harnesses/enrollonbehalfof-1.svg @@ -1,18 +1 @@ - -NTAuthStoreForTrustedForNTAuthPublishedToPublishedToPublishedToRootCAForEnterpriseCAForEnrollOnBehalfOfEnrollOnBehalfOfDomain1CertTemplate1-1schemaversion:2ekus:["2.5.29.37.0"]NTAuthStore1EnterpriseCA1CertTemplate1-2schemaversion:1ekus:["2.5.29.37.0"]CertTemplate1-3schemaversion:2ekus:["2.5.29.37.0"]RootCA1 +NTAuthStoreForTrustedForNTAuthPublishedToPublishedToPublishedToRootCAForEnterpriseCAForEnrollOnBehalfOfEnrollOnBehalfOfEnrollOnBehalfOfDomain1CertTemplate1-1schemaversion:2effectiveekus:["2.5.29.37.0"]NTAuthStore1EnterpriseCA1CertTemplate1-2schemaversion:1effectiveekus:["2.5.29.37.0"]CertTemplate1-3schemaversion:2effectiveekus:["2.5.29.37.0"]RootCA1 \ No newline at end of file diff --git a/cmd/api/src/test/integration/harnesses/enrollonbehalfof-2.json b/cmd/api/src/test/integration/harnesses/enrollonbehalfof-2.json index ee3e2a4b43..607f78cbef 100644 --- a/cmd/api/src/test/integration/harnesses/enrollonbehalfof-2.json +++ b/cmd/api/src/test/integration/harnesses/enrollonbehalfof-2.json @@ -1,10 +1,63 @@ { + "style": { + "font-family": "sans-serif", + "background-color": "#ffffff", + "background-image": "", + "background-size": "100%", + "node-color": "#ffffff", + "border-width": 4, + "border-color": "#000000", + "radius": 50, + "node-padding": 5, + "node-margin": 2, + "outside-position": "auto", + "node-icon-image": "", + "node-background-image": "", + "icon-position": "inside", + "icon-size": 64, + "caption-position": "inside", + "caption-max-width": 200, + "caption-color": "#000000", + "caption-font-size": 50, + "caption-font-weight": "normal", + "label-position": "inside", + "label-display": "pill", + "label-color": "#000000", + "label-background-color": "#ffffff", + "label-border-color": "#000000", + "label-border-width": 4, + "label-font-size": 40, + "label-padding": 5, + "label-margin": 4, + "directionality": "directed", + "detail-position": "inline", + "detail-orientation": "parallel", + "arrow-width": 5, + "arrow-color": "#000000", + "margin-start": 5, + "margin-end": 5, + "margin-peer": 20, + "attachment-start": "normal", + "attachment-end": "normal", + "relationship-icon-image": "", + "type-color": "#000000", + "type-background-color": "#ffffff", + "type-border-color": "#000000", + "type-border-width": 0, + "type-font-size": 16, + "type-padding": 5, + "property-position": "outside", + "property-alignment": "colon", + "property-color": "#000000", + "property-font-size": 16, + "property-font-weight": "normal" + }, "nodes": [ { "id": "n0", "position": { - "x": -569.1685177598522, - "y": -1021.0927494329366 + "x": 657.3454879680903, + "y": 50 }, "caption": "Domain2", "labels": [], @@ -14,10 +67,10 @@ } }, { - "id": "n2", + "id": "n1", "position": { - "x": -811.4923275967599, - "y": -1021.0927494329366 + "x": 415.0216781311826, + "y": 50 }, "caption": "NTAuthStore2", "labels": [], @@ -27,10 +80,10 @@ } }, { - "id": "n5", + "id": "n2", "position": { - "x": -811.4923275967599, - "y": -743.1164660081513 + "x": 415.0216781311826, + "y": 327.97628342478527 }, "caption": "EnterpriseCA2", "labels": [], @@ -40,10 +93,10 @@ } }, { - "id": "n13", + "id": "n3", "position": { - "x": -569.1685177598522, - "y": -743.1164660081513 + "x": 657.3454879680903, + "y": 327.97628342478527 }, "caption": "RootCA2", "labels": [], @@ -53,40 +106,42 @@ } }, { - "id": "n14", + "id": "n4", "position": { - "x": -1151.5140057279425, - "y": -743.1164660081513 + "x": 75, + "y": 327.97628342478527 }, "caption": "CertTemplate2-1", "labels": [], "properties": { - "effectiveekus": "[\"1.3.6.1.4.1.311.20.2.1\"]" + "effectiveekus": "[\"1.3.6.1.4.1.311.20.2.1\"]", + "schemaversion": "2" }, "style": { "node-color": "#fda1ff" } }, { - "id": "n15", + "id": "n5", "position": { - "x": -1151.5140057279425, - "y": -546.8048586088046 + "x": 75, + "y": 524.287890824132 }, "caption": "CertTemplate2-2", "labels": [], "properties": { - "effectiveekus": "[\"1.3.6.1.4.1.311.20.2.1\", \"2.5.29.37.0\"]" + "effectiveekus": "[\"1.3.6.1.4.1.311.20.2.1\", \"2.5.29.37.0\"]", + "schemaversion": "2" }, "style": { "node-color": "#fda1ff" } }, { - "id": "n16", + "id": "n6", "position": { - "x": -981.5031666623508, - "y": -448.6490549091318 + "x": 245.01083906559165, + "y": 622.4436945238048 }, "caption": "CertTemplate2-3", "labels": [], @@ -101,10 +156,10 @@ } }, { - "id": "n17", + "id": "n7", "position": { - "x": -695.4923275967599, - "y": -448.6490549091318 + "x": 531.0216781311826, + "y": 622.4436945238048 }, "caption": "CertTemplate2-4", "labels": [], @@ -117,29 +172,12 @@ "style": { "node-color": "#fda1ff" } - }, - { - "id": "n18", - "position": { - "x": -517.02491649774, - "y": -448.6490549091315 - }, - "caption": "CertTemplate2-5", - "labels": [], - "properties": { - "effectiveekus": "[]", - "schemaversion": "1", - "subjectaltrequiresupn": "true" - }, - "style": { - "node-color": "#fda1ff" - } } ], "relationships": [ { "id": "n0", - "fromId": "n2", + "fromId": "n1", "toId": "n0", "type": "NTAuthStoreFor", "properties": {}, @@ -147,141 +185,69 @@ }, { "id": "n1", - "fromId": "n5", - "toId": "n2", + "fromId": "n2", + "toId": "n1", "type": "TrustedForNTAuth", "properties": {}, "style": {} }, { - "id": "n9", - "fromId": "n13", + "id": "n2", + "fromId": "n3", "toId": "n0", "type": "RootCAFor", "properties": {}, "style": {} }, { - "id": "n10", - "fromId": "n5", - "toId": "n13", + "id": "n3", + "fromId": "n2", + "toId": "n3", "type": "EnterpriseCAFor", "properties": {}, "style": {} }, { - "id": "n11", - "fromId": "n14", - "toId": "n5", - "type": "PublishedTo", - "properties": {}, - "style": {} - }, - { - "id": "n12", - "fromId": "n15", - "toId": "n5", + "id": "n4", + "fromId": "n4", + "toId": "n2", "type": "PublishedTo", "properties": {}, "style": {} }, { - "id": "n13", - "fromId": "n16", - "toId": "n5", + "id": "n5", + "fromId": "n5", + "toId": "n2", "type": "PublishedTo", "properties": {}, "style": {} }, { - "id": "n14", - "fromId": "n17", - "toId": "n5", + "id": "n6", + "fromId": "n6", + "toId": "n2", "type": "PublishedTo", "properties": {}, "style": {} }, { - "id": "n15", - "type": "EnrollOnBehalfOf", - "style": { - "arrow-color": "#a4dd00" - }, - "properties": {}, - "toId": "n16", - "fromId": "n14" - }, - { - "id": "n16", - "fromId": "n18", - "toId": "n5", + "id": "n7", + "fromId": "n7", + "toId": "n2", "type": "PublishedTo", "properties": {}, "style": {} }, { - "id": "n17", - "fromId": "n18", - "toId": "n18", + "id": "n8", + "fromId": "n4", + "toId": "n6", "type": "EnrollOnBehalfOf", "properties": {}, "style": { - "type-color": "#4d4d4d", "arrow-color": "#a4dd00" } } - ], - "style": { - "font-family": "sans-serif", - "background-color": "#ffffff", - "background-image": "", - "background-size": "100%", - "node-color": "#ffffff", - "border-width": 4, - "border-color": "#000000", - "radius": 50, - "node-padding": 5, - "node-margin": 2, - "outside-position": "auto", - "node-icon-image": "", - "node-background-image": "", - "icon-position": "inside", - "icon-size": 64, - "caption-position": "inside", - "caption-max-width": 200, - "caption-color": "#000000", - "caption-font-size": 50, - "caption-font-weight": "normal", - "label-position": "inside", - "label-display": "pill", - "label-color": "#000000", - "label-background-color": "#ffffff", - "label-border-color": "#000000", - "label-border-width": 4, - "label-font-size": 40, - "label-padding": 5, - "label-margin": 4, - "directionality": "directed", - "detail-position": "inline", - "detail-orientation": "parallel", - "arrow-width": 5, - "arrow-color": "#000000", - "margin-start": 5, - "margin-end": 5, - "margin-peer": 20, - "attachment-start": "normal", - "attachment-end": "normal", - "relationship-icon-image": "", - "type-color": "#000000", - "type-background-color": "#ffffff", - "type-border-color": "#000000", - "type-border-width": 0, - "type-font-size": 16, - "type-padding": 5, - "property-position": "outside", - "property-alignment": "colon", - "property-color": "#000000", - "property-font-size": 16, - "property-font-weight": "normal" - } + ] } \ No newline at end of file diff --git a/cmd/api/src/test/integration/harnesses/enrollonbehalfof-2.svg b/cmd/api/src/test/integration/harnesses/enrollonbehalfof-2.svg index dd203c5b22..d8d8ec0fcb 100644 --- a/cmd/api/src/test/integration/harnesses/enrollonbehalfof-2.svg +++ b/cmd/api/src/test/integration/harnesses/enrollonbehalfof-2.svg @@ -1,18 +1 @@ - -NTAuthStoreForTrustedForNTAuthRootCAForEnterpriseCAForPublishedToPublishedToPublishedToPublishedToEnrollOnBehalfOfPublishedToEnrollOnBehalfOfDomain2NTAuthStore2EnterpriseCA2RootCA2CertTemplate2-1ekus:["1.3.6.1.4.1.311.20.2.1"]CertTemplate2-2ekus:["1.3.6.1.4.1.311.20.2.1", "2.5.29.37.0"]CertTemplate2-3ekus:[]schemaversion:2authorizedsignatures:1applicationpolicies:["1.3.6.1.4.1.311.20.2.1"]CertTemplate2-4ekus:[]schemaversion:2authorizedsignatures:1applicationpolicies:[]CertTemplate2-5ekus:[]schemaversion:1subjectaltrequiresupn:true +NTAuthStoreForTrustedForNTAuthRootCAForEnterpriseCAForPublishedToPublishedToPublishedToPublishedToEnrollOnBehalfOfDomain2NTAuthStore2EnterpriseCA2RootCA2CertTemplate2-1effectiveekus:["1.3.6.1.4.1.311.20.2.1"]schemaversion:2CertTemplate2-2effectiveekus:["1.3.6.1.4.1.311.20.2.1", "2.5.29.37.0"]schemaversion:2CertTemplate2-3effectiveekus:[]schemaversion:2authorizedsignatures:1applicationpolicies:["1.3.6.1.4.1.311.20.2.1"]CertTemplate2-4effectiveekus:[]schemaversion:2authorizedsignatures:1applicationpolicies:[] \ No newline at end of file diff --git a/cmd/api/src/test/integration/harnesses/enrollonbehalfof-3.json b/cmd/api/src/test/integration/harnesses/enrollonbehalfof-3.json new file mode 100644 index 0000000000..e0537e9ec6 --- /dev/null +++ b/cmd/api/src/test/integration/harnesses/enrollonbehalfof-3.json @@ -0,0 +1,256 @@ +{ + "style": { + "font-family": "sans-serif", + "background-color": "#ffffff", + "background-image": "", + "background-size": "100%", + "node-color": "#ffffff", + "border-width": 4, + "border-color": "#000000", + "radius": 50, + "node-padding": 5, + "node-margin": 2, + "outside-position": "auto", + "node-icon-image": "", + "node-background-image": "", + "icon-position": "inside", + "icon-size": 64, + "caption-position": "inside", + "caption-max-width": 200, + "caption-color": "#000000", + "caption-font-size": 50, + "caption-font-weight": "normal", + "label-position": "inside", + "label-display": "pill", + "label-color": "#000000", + "label-background-color": "#ffffff", + "label-border-color": "#000000", + "label-border-width": 4, + "label-font-size": 40, + "label-padding": 5, + "label-margin": 4, + "directionality": "directed", + "detail-position": "inline", + "detail-orientation": "parallel", + "arrow-width": 5, + "arrow-color": "#000000", + "margin-start": 5, + "margin-end": 5, + "margin-peer": 20, + "attachment-start": "normal", + "attachment-end": "normal", + "relationship-icon-image": "", + "type-color": "#000000", + "type-background-color": "#ffffff", + "type-border-color": "#000000", + "type-border-width": 0, + "type-font-size": 16, + "type-padding": 5, + "property-position": "outside", + "property-alignment": "colon", + "property-color": "#000000", + "property-font-size": 16, + "property-font-weight": "normal" + }, + "nodes": [ + { + "id": "n0", + "position": { + "x": 675.9551990267428, + "y": 50 + }, + "caption": "Domain1", + "labels": [], + "properties": {}, + "style": { + "node-color": "#68ccca" + } + }, + { + "id": "n1", + "position": { + "x": -44.95912785436991, + "y": 327.97628342478527 + }, + "caption": "CertTemplate1-1", + "labels": [], + "properties": { + "schemaversion": "2", + "effectiveekus": "[\"2.5.29.37.0\"]" + }, + "style": { + "node-color": "#fda1ff" + } + }, + { + "id": "n2", + "position": { + "x": 433.6313891898351, + "y": 50 + }, + "caption": "NTAuthStore1", + "labels": [], + "properties": {}, + "style": { + "node-color": "#7b64ff" + } + }, + { + "id": "n3", + "position": { + "x": 433.6313891898351, + "y": 327.97628342478527 + }, + "caption": "EnterpriseCA1", + "labels": [], + "properties": {}, + "style": { + "node-color": "#b0bc00" + } + }, + { + "id": "n4", + "position": { + "x": 194.3361306677326, + "y": 557.3609078601627 + }, + "caption": "CertTemplate1-2", + "labels": [], + "properties": { + "schemaversion": "1", + "effectiveekus": "[\"2.5.29.37.0\"]" + }, + "style": { + "node-color": "#fda1ff" + } + }, + { + "id": "n5", + "position": { + "x": 433.6313891898351, + "y": 796.6561663822652 + }, + "caption": "CertTemplate1-3", + "labels": [], + "properties": { + "schemaversion": "2", + "effectiveekus": "[\"2.5.29.37.0\"]" + }, + "style": { + "node-color": "#fda1ff" + } + }, + { + "id": "n6", + "position": { + "x": 675.9551990267428, + "y": 327.97628342478527 + }, + "caption": "RootCA1", + "labels": [], + "properties": {}, + "style": { + "node-color": "#e27300" + } + }, + { + "id": "n7", + "position": { + "x": 433.6313891898351, + "y": 500.5114025285298 + }, + "caption": "EnterpriseCA2", + "style": { + "node-color": "#b0bc00" + }, + "labels": [], + "properties": {} + } + ], + "relationships": [ + { + "id": "n0", + "fromId": "n2", + "toId": "n0", + "type": "NTAuthStoreFor", + "properties": {}, + "style": {} + }, + { + "id": "n1", + "fromId": "n3", + "toId": "n2", + "type": "TrustedForNTAuth", + "properties": {}, + "style": {} + }, + { + "id": "n2", + "fromId": "n1", + "toId": "n3", + "type": "PublishedTo", + "properties": {}, + "style": {} + }, + { + "id": "n3", + "fromId": "n4", + "toId": "n3", + "type": "PublishedTo", + "properties": {}, + "style": {} + }, + { + "id": "n5", + "fromId": "n6", + "toId": "n0", + "type": "RootCAFor", + "properties": {}, + "style": {} + }, + { + "id": "n6", + "fromId": "n3", + "toId": "n6", + "type": "EnterpriseCAFor", + "properties": {}, + "style": {} + }, + { + "id": "n7", + "fromId": "n1", + "toId": "n4", + "type": "EnrollOnBehalfOf", + "properties": {}, + "style": { + "arrow-color": "#68ccca" + } + }, + { + "id": "n12", + "type": "PublishedTo", + "fromId": "n5", + "toId": "n7", + "style": {}, + "properties": {} + }, + { + "id": "n13", + "type": "EnterpriseCAFor", + "fromId": "n7", + "toId": "n6", + "style": {}, + "properties": {} + }, + { + "id": "n14", + "type": "EnrollOnBehalfOf", + "style": { + "arrow-color": "#68ccca" + }, + "properties": {}, + "fromId": "n4", + "toId": "n4" + } + ] +} \ No newline at end of file diff --git a/cmd/api/src/test/integration/harnesses/enrollonbehalfof-3.svg b/cmd/api/src/test/integration/harnesses/enrollonbehalfof-3.svg new file mode 100644 index 0000000000..d7192c6074 --- /dev/null +++ b/cmd/api/src/test/integration/harnesses/enrollonbehalfof-3.svg @@ -0,0 +1 @@ +NTAuthStoreForTrustedForNTAuthPublishedToPublishedToRootCAForEnterpriseCAForEnrollOnBehalfOfPublishedToEnterpriseCAForEnrollOnBehalfOfDomain1CertTemplate1-1schemaversion:2effectiveekus:["2.5.29.37.0"]NTAuthStore1EnterpriseCA1CertTemplate1-2schemaversion:1effectiveekus:["2.5.29.37.0"]CertTemplate1-3schemaversion:2effectiveekus:["2.5.29.37.0"]RootCA1EnterpriseCA2 \ No newline at end of file diff --git a/packages/go/analysis/ad/adcs.go b/packages/go/analysis/ad/adcs.go index 537b0b0770..ac1f9a76cb 100644 --- a/packages/go/analysis/ad/adcs.go +++ b/packages/go/analysis/ad/adcs.go @@ -47,30 +47,33 @@ func PostADCS(ctx context.Context, db graph.Database, groupExpansions impact.Pat return &analysis.AtomicPostProcessingStats{}, fmt.Errorf("failed fetching domain nodes: %w", err) } else if step1Stats, err := postADCSPreProcessStep1(ctx, db, enterpriseCertAuthorities, rootCertAuthorities, aiaCertAuthorities, certTemplates); err != nil { return &analysis.AtomicPostProcessingStats{}, fmt.Errorf("failed adcs pre-processing step 1: %w", err) - } else if step2Stats, err := postADCSPreProcessStep2(ctx, db, certTemplates); err != nil { - return &analysis.AtomicPostProcessingStats{}, fmt.Errorf("failed adcs pre-processing step 2: %w", err) } else { - operation := analysis.NewPostRelationshipOperation(ctx, db, "ADCS Post Processing") - - operation.Stats.Merge(step1Stats) - operation.Stats.Merge(step2Stats) - var cache = NewADCSCache() cache.BuildCache(ctx, db, enterpriseCertAuthorities, certTemplates, domains) - for _, domain := range domains { - innerDomain := domain + if step2Stats, err := postADCSPreProcessStep2(ctx, db, domains, enterpriseCertAuthorities, certTemplates, cache); err != nil { + return &analysis.AtomicPostProcessingStats{}, fmt.Errorf("failed adcs pre-processing step 2: %w", err) + } else { + + operation := analysis.NewPostRelationshipOperation(ctx, db, "ADCS Post Processing") + + operation.Stats.Merge(step1Stats) + operation.Stats.Merge(step2Stats) - for _, enterpriseCA := range enterpriseCertAuthorities { - innerEnterpriseCA := enterpriseCA + for _, domain := range domains { + innerDomain := domain - if cache.DoesCAChainProperlyToDomain(innerEnterpriseCA, innerDomain) { - processEnterpriseCAWithValidCertChainToDomain(innerEnterpriseCA, innerDomain, groupExpansions, cache, operation) + for _, enterpriseCA := range enterpriseCertAuthorities { + innerEnterpriseCA := enterpriseCA + + if cache.DoesCAChainProperlyToDomain(innerEnterpriseCA, innerDomain) { + processEnterpriseCAWithValidCertChainToDomain(innerEnterpriseCA, innerDomain, groupExpansions, cache, operation) + } } } - } + return &operation.Stats, operation.Done() - return &operation.Stats, operation.Done() + } } } @@ -97,10 +100,10 @@ func postADCSPreProcessStep1(ctx context.Context, db graph.Database, enterpriseC } // postADCSPreProcessStep2 Processes the edges that are dependent on those processed in postADCSPreProcessStep1 -func postADCSPreProcessStep2(ctx context.Context, db graph.Database, certTemplates []*graph.Node) (*analysis.AtomicPostProcessingStats, error) { +func postADCSPreProcessStep2(ctx context.Context, db graph.Database, domains, enterpriseCertAuthorities, certTemplates []*graph.Node, cache ADCSCache) (*analysis.AtomicPostProcessingStats, error) { operation := analysis.NewPostRelationshipOperation(ctx, db, "ADCS Post Processing Step 2") - if err := PostEnrollOnBehalfOf(certTemplates, operation); err != nil { + if err := PostEnrollOnBehalfOf(domains, enterpriseCertAuthorities, certTemplates, cache, operation); err != nil { operation.Done() return &analysis.AtomicPostProcessingStats{}, fmt.Errorf("failed post processing for %s: %w", ad.EnrollOnBehalfOf.String(), err) } else { diff --git a/packages/go/analysis/ad/esc3.go b/packages/go/analysis/ad/esc3.go index 2406e0081b..28abe1fcec 100644 --- a/packages/go/analysis/ad/esc3.go +++ b/packages/go/analysis/ad/esc3.go @@ -142,60 +142,71 @@ func PostADCSESC3(ctx context.Context, tx graph.Transaction, outC chan<- analysi return nil } -func PostEnrollOnBehalfOf(certTemplates []*graph.Node, operation analysis.StatTrackedOperation[analysis.CreatePostRelationshipJob]) error { +func PostEnrollOnBehalfOf(domains, enterpriseCertAuthorities, certTemplates []*graph.Node, cache ADCSCache, operation analysis.StatTrackedOperation[analysis.CreatePostRelationshipJob]) error { versionOneTemplates := make([]*graph.Node, 0) versionTwoTemplates := make([]*graph.Node, 0) - for _, node := range certTemplates { if version, err := node.Properties.Get(ad.SchemaVersion.String()).Float64(); errors.Is(err, graph.ErrPropertyNotFound) { log.Warnf("Did not get schema version for cert template %d: %v", node.ID, err) } else if err != nil { log.Errorf("Error getting schema version for cert template %d: %v", node.ID, err) + } else if version == 1 { + versionOneTemplates = append(versionOneTemplates, node) + } else if version >= 2 { + versionTwoTemplates = append(versionTwoTemplates, node) } else { - if version == 1 { - versionOneTemplates = append(versionOneTemplates, node) - } else if version >= 2 { - versionTwoTemplates = append(versionTwoTemplates, node) - } else { - log.Warnf("Got cert template %d with an invalid version %d", node.ID, version) - } + log.Warnf("Got cert template %d with an invalid version %d", node.ID, version) } } - operation.Operation.SubmitReader(func(ctx context.Context, tx graph.Transaction, outC chan<- analysis.CreatePostRelationshipJob) error { - if results, err := EnrollOnBehalfOfVersionTwo(tx, versionTwoTemplates, certTemplates); err != nil { - return err - } else { - for _, result := range results { - if !channels.Submit(ctx, outC, result) { - return nil - } - } + for _, domain := range domains { + innerDomain := domain - return nil - } - }) + for _, enterpriseCA := range enterpriseCertAuthorities { + innerEnterpriseCA := enterpriseCA - operation.Operation.SubmitReader(func(ctx context.Context, tx graph.Transaction, outC chan<- analysis.CreatePostRelationshipJob) error { - if results, err := EnrollOnBehalfOfVersionOne(tx, versionOneTemplates, certTemplates); err != nil { - return err - } else { - for _, result := range results { - if !channels.Submit(ctx, outC, result) { + if cache.DoesCAChainProperlyToDomain(innerEnterpriseCA, innerDomain) { + if publishedCertTemplates := cache.GetPublishedTemplateCache(enterpriseCA.ID); len(publishedCertTemplates) == 0 { return nil + } else { + operation.Operation.SubmitReader(func(ctx context.Context, tx graph.Transaction, outC chan<- analysis.CreatePostRelationshipJob) error { + if results, err := EnrollOnBehalfOfVersionTwo(tx, versionTwoTemplates, publishedCertTemplates, innerDomain); err != nil { + return err + } else { + for _, result := range results { + if !channels.Submit(ctx, outC, result) { + return nil + } + } + + return nil + } + }) + + operation.Operation.SubmitReader(func(ctx context.Context, tx graph.Transaction, outC chan<- analysis.CreatePostRelationshipJob) error { + if results, err := EnrollOnBehalfOfVersionOne(tx, versionOneTemplates, publishedCertTemplates, innerDomain); err != nil { + return err + } else { + for _, result := range results { + if !channels.Submit(ctx, outC, result) { + return nil + } + } + + return nil + } + }) } } - - return nil } - }) + } return nil } -func EnrollOnBehalfOfVersionTwo(tx graph.Transaction, versionTwoCertTemplates, allCertTemplates []*graph.Node) ([]analysis.CreatePostRelationshipJob, error) { +func EnrollOnBehalfOfVersionTwo(tx graph.Transaction, versionTwoCertTemplates, publishedTemplates []*graph.Node, domainNode *graph.Node) ([]analysis.CreatePostRelationshipJob, error) { results := make([]analysis.CreatePostRelationshipJob, 0) - for _, certTemplateOne := range allCertTemplates { + for _, certTemplateOne := range publishedTemplates { if hasBadEku, err := certTemplateHasEku(certTemplateOne, EkuAnyPurpose); errors.Is(err, graph.ErrPropertyNotFound) { log.Warnf("Did not get EffectiveEKUs for cert template %d: %v", certTemplateOne.ID, err) } else if err != nil { @@ -208,12 +219,6 @@ func EnrollOnBehalfOfVersionTwo(tx graph.Transaction, versionTwoCertTemplates, a log.Errorf("Error getting EffectiveEKUs for cert template %d: %v", certTemplateOne.ID, err) } else if !hasEku { continue - } else if domainNode, err := getDomainForCertTemplate(tx, certTemplateOne); err != nil { - log.Errorf("Error getting domain node for cert template %d: %v", certTemplateOne.ID, err) - } else if isLinked, err := DoesCertTemplateLinkToDomain(tx, certTemplateOne, domainNode); err != nil { - log.Errorf("Error fetching paths from cert template %d to domain: %v", certTemplateOne.ID, err) - } else if !isLinked { - continue } else { for _, certTemplateTwo := range versionTwoCertTemplates { if certTemplateOne.ID == certTemplateTwo.ID { @@ -260,10 +265,10 @@ func certTemplateHasEku(certTemplate *graph.Node, targetEkus ...string) (bool, e } } -func EnrollOnBehalfOfVersionOne(tx graph.Transaction, versionOneCertTemplates []*graph.Node, allCertTemplates []*graph.Node) ([]analysis.CreatePostRelationshipJob, error) { +func EnrollOnBehalfOfVersionOne(tx graph.Transaction, versionOneCertTemplates []*graph.Node, publishedTemplates []*graph.Node, domainNode *graph.Node) ([]analysis.CreatePostRelationshipJob, error) { results := make([]analysis.CreatePostRelationshipJob, 0) - for _, certTemplateOne := range allCertTemplates { + for _, certTemplateOne := range publishedTemplates { //prefilter as much as we can first if hasEku, err := certTemplateHasEkuOrAll(certTemplateOne, EkuCertRequestAgent, EkuAnyPurpose); errors.Is(err, graph.ErrPropertyNotFound) { log.Warnf("Error checking ekus for certtemplate %d: %v", certTemplateOne.ID, err) @@ -271,12 +276,6 @@ func EnrollOnBehalfOfVersionOne(tx graph.Transaction, versionOneCertTemplates [] log.Errorf("Error checking ekus for certtemplate %d: %v", certTemplateOne.ID, err) } else if !hasEku { continue - } else if domainNode, err := getDomainForCertTemplate(tx, certTemplateOne); err != nil { - log.Errorf("Error getting domain node for certtemplate %d: %v", certTemplateOne.ID, err) - } else if hasPath, err := DoesCertTemplateLinkToDomain(tx, certTemplateOne, domainNode); err != nil { - log.Errorf("Error fetching paths from certtemplate %d to domain: %v", certTemplateOne.ID, err) - } else if !hasPath { - continue } else { for _, certTemplateTwo := range versionOneCertTemplates { if hasPath, err := DoesCertTemplateLinkToDomain(tx, certTemplateTwo, domainNode); err != nil { @@ -359,19 +358,9 @@ func certTemplateHasEkuOrAll(certTemplate *graph.Node, targetEkus ...string) (bo } } -func getDomainForCertTemplate(tx graph.Transaction, certTemplate *graph.Node) (*graph.Node, error) { - if domainSid, err := certTemplate.Properties.Get(ad.DomainSID.String()).String(); err != nil { - return &graph.Node{}, err - } else if domainNode, err := analysis.FetchNodeByObjectID(tx, domainSid); err != nil { - return &graph.Node{}, err - } else { - return domainNode, nil - } -} - func GetADCSESC3EdgeComposition(ctx context.Context, db graph.Database, edge *graph.Relationship) (graph.PathSet, error) { /* - MATCH p1 = (x)-[:MemberOf*0..]->()-[:GenericAll|Enroll|AllExtendedRights]->(ct1:CertTemplate)-[:PublishedTo]->(eca1:EnterpriseCA) + MATCH p1 = (x)-[:MemberOf*0..]->()-[:GenericAll|Enroll|AllExtendedRights]->(ct1:CertTemplate)-[:PublishedTo]->(eca1:EnterpriseCA)-[:TrustedForNTAuth]->(:NTAuthStore)-[:NTAuthStoreFor]->(d) WHERE x.objectid = "S-1-5-21-83094068-830424655-2031507174-500" AND d.objectid = "S-1-5-21-83094068-830424655-2031507174" AND ct1.requiresmanagerapproval = false @@ -483,7 +472,7 @@ func GetADCSESC3EdgeComposition(ctx context.Context, db graph.Database, edge *gr for _, n := range startNodes.Slice() { if err := traversalInst.BreadthFirst(ctx, traversal.Plan{ Root: n, - Driver: ADCSESC3Path1Pattern(enterpriseCANodes).Do(func(terminal *graph.PathSegment) error { + Driver: ADCSESC3Path1Pattern(edge.EndID, enterpriseCANodes).Do(func(terminal *graph.PathSegment) error { certTemplateNode := terminal.Search(func(nextSegment *graph.PathSegment) bool { return nextSegment.Node.Kinds.ContainsOneOf(ad.CertTemplate) }) @@ -673,7 +662,7 @@ func GetADCSESC3EdgeComposition(ctx context.Context, db graph.Database, edge *gr return paths, nil } -func ADCSESC3Path1Pattern(enterpriseCAs cardinality.Duplex[uint64]) traversal.PatternContinuation { +func ADCSESC3Path1Pattern(domainId graph.ID, enterpriseCAs cardinality.Duplex[uint64]) traversal.PatternContinuation { return traversal.NewPattern().OutboundWithDepth(0, 0, query.And( query.Kind(query.Relationship(), ad.MemberOf), query.Kind(query.End(), ad.Group), @@ -696,6 +685,14 @@ func ADCSESC3Path1Pattern(enterpriseCAs cardinality.Duplex[uint64]) traversal.Pa query.KindIn(query.Relationship(), ad.PublishedTo), query.InIDs(query.End(), graph.DuplexToGraphIDs(enterpriseCAs)...), query.Kind(query.End(), ad.EnterpriseCA), + )). + Outbound(query.And( + query.KindIn(query.Relationship(), ad.TrustedForNTAuth), + query.Kind(query.End(), ad.NTAuthStore), + )). + Outbound(query.And( + query.KindIn(query.Relationship(), ad.NTAuthStoreFor), + query.Equals(query.EndID(), domainId), )) }