Skip to content

Commit

Permalink
Merge branch 'main' of github.com:SpecterOps/BloodHound into BED-4624
Browse files Browse the repository at this point in the history
  • Loading branch information
iustinum committed Dec 12, 2024
2 parents c2e2e96 + b4bd50c commit 81d158d
Show file tree
Hide file tree
Showing 32 changed files with 1,229 additions and 457 deletions.
85 changes: 71 additions & 14 deletions cmd/api/src/analysis/ad/adcs_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand All @@ -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
})
Expand Down
4 changes: 2 additions & 2 deletions cmd/api/src/api/v2/datapipe_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE2.0
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDXLicenseIdentifier: Apache2.0
// SPDX-License-Identifier: Apache-2.0

//go:build serial_integration
// +build serial_integration
Expand Down
3 changes: 3 additions & 0 deletions cmd/api/src/database/migration/migrations/v6.3.0.sql
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,6 @@ UPDATE feature_flags SET enabled = true WHERE key = 'updated_posture_page';

-- Fix users in bad state due to sso bug
DELETE FROM auth_secrets WHERE id IN (SELECT auth_secrets.id FROM auth_secrets JOIN users ON users.id = auth_secrets.user_id WHERE users.sso_provider_id IS NOT NULL);

-- Set the `oidc_support` feature flag to true
UPDATE feature_flags SET enabled = true WHERE key = 'oidc_support';
99 changes: 77 additions & 22 deletions cmd/api/src/test/integration/harnesses.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand All @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit 81d158d

Please sign in to comment.