Skip to content

Commit

Permalink
Merge branch 'main' of github.com:SpecterOps/BloodHound into BED-4069
Browse files Browse the repository at this point in the history
  • Loading branch information
benwaples committed Feb 5, 2024
2 parents 2514e78 + f14442a commit 89f313f
Show file tree
Hide file tree
Showing 56 changed files with 5,968 additions and 1,366 deletions.
2 changes: 2 additions & 0 deletions .github/config/integration.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
"collectors_base_path": "/tmp/collectors",
"log_level": "ERROR",
"log_path": "bhapi.log",
"enable_startup_wait_period": false,
"datapipe_interval": 1,
"features": {
"enable_auth": true
},
Expand Down
244 changes: 242 additions & 2 deletions cmd/api/src/analysis/ad/adcs_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1940,13 +1940,13 @@ func TestADCSESC10a(t *testing.T) {
if results, err := ops.FetchRelationships(tx.Relationships().Filterf(func() graph.Criteria {
return query.Kind(query.Relationship(), ad.ADCSESC10a)
})); err != nil {
t.Fatalf("error fetching esc9a edges in integration test; %v", err)
t.Fatalf("error fetching esc10a edges in integration test; %v", err)
} else {
assert.Equal(t, 1, len(results))
edge := results[0]

if edgeComp, err := ad2.GetEdgeCompositionPath(context.Background(), db, edge); err != nil {
t.Fatalf("error getting edge composition for esc9: %v", err)
t.Fatalf("error getting edge composition for esc10a: %v", err)
} else {
nodes := edgeComp.AllNodes().Slice()
assert.Contains(t, nodes, harness.ESC10aHarnessECA.Group1)
Expand Down Expand Up @@ -2011,3 +2011,243 @@ func TestADCSESC10a(t *testing.T) {
})
})
}

func TestADCSESC10b(t *testing.T) {
testContext := integration.NewGraphTestContext(t, graphschema.DefaultGraphSchema())

testContext.DatabaseTestWithSetup(func(harness *integration.HarnessDetails) error {
harness.ESC10bPrincipalHarness.Setup(testContext)
return nil
}, func(harness integration.HarnessDetails, db graph.Database) {
operation := analysis.NewPostRelationshipOperation(context.Background(), db, "ADCS Post Process Test - ESC10b")

groupExpansions, enterpriseCertAuthorities, _, domains, cache, err := FetchADCSPrereqs(db)
require.Nil(t, err)

for _, domain := range domains {
innerDomain := domain

for _, enterpriseCA := range enterpriseCertAuthorities {
if cache.DoesCAChainProperlyToDomain(enterpriseCA, innerDomain) {
innerEnterpriseCA := enterpriseCA

operation.Operation.SubmitReader(func(ctx context.Context, tx graph.Transaction, outC chan<- analysis.CreatePostRelationshipJob) error {
if err := ad2.PostADCSESC10b(ctx, tx, outC, groupExpansions, innerEnterpriseCA, innerDomain, cache); err != nil {
t.Logf("failed post processing for %s: %v", ad.ADCSESC10b.String(), err)
} else {
return nil
}

return nil
})
}
}
}
err = operation.Done()
require.Nil(t, err)

db.ReadTransaction(context.Background(), func(tx graph.Transaction) error {
if results, err := ops.FetchStartNodes(tx.Relationships().Filterf(func() graph.Criteria {
return query.Kind(query.Relationship(), ad.ADCSESC10b)
})); err != nil {
t.Fatalf("error fetching esc10b edges in integration test; %v", err)
} else {
require.Equal(t, 6, len(results))

require.True(t, results.Contains(harness.ESC10bPrincipalHarness.Group1))
require.True(t, results.Contains(harness.ESC10bPrincipalHarness.Group2))
require.True(t, results.Contains(harness.ESC10bPrincipalHarness.Group3))
require.True(t, results.Contains(harness.ESC10bPrincipalHarness.Group4))
require.True(t, results.Contains(harness.ESC10bPrincipalHarness.Group5))
}
return nil
})
})

testContext.DatabaseTestWithSetup(func(harness *integration.HarnessDetails) error {
harness.ESC10bHarness1.Setup(testContext)
return nil
}, func(harness integration.HarnessDetails, db graph.Database) {
operation := analysis.NewPostRelationshipOperation(context.Background(), db, "ADCS Post Process Test - ESC10b")

groupExpansions, enterpriseCertAuthorities, _, domains, cache, err := FetchADCSPrereqs(db)
require.Nil(t, err)

for _, domain := range domains {
innerDomain := domain

for _, enterpriseCA := range enterpriseCertAuthorities {
if cache.DoesCAChainProperlyToDomain(enterpriseCA, innerDomain) {
innerEnterpriseCA := enterpriseCA

operation.Operation.SubmitReader(func(ctx context.Context, tx graph.Transaction, outC chan<- analysis.CreatePostRelationshipJob) error {
if err := ad2.PostADCSESC10b(ctx, tx, outC, groupExpansions, innerEnterpriseCA, innerDomain, cache); err != nil {
t.Logf("failed post processing for %s: %v", ad.ADCSESC10b.String(), err)
} else {
return nil
}

return nil
})
}
}
}
err = operation.Done()
require.Nil(t, err)

db.ReadTransaction(context.Background(), func(tx graph.Transaction) error {
if results, err := ops.FetchStartNodes(tx.Relationships().Filterf(func() graph.Criteria {
return query.Kind(query.Relationship(), ad.ADCSESC10b)
})); err != nil {
t.Fatalf("error fetching esc10b edges in integration test; %v", err)
} else {
require.Equal(t, 2, len(results))

require.True(t, results.Contains(harness.ESC10bHarness1.Group1))
require.True(t, results.Contains(harness.ESC10bHarness1.Group2))

}
return nil
})
})

testContext.DatabaseTestWithSetup(func(harness *integration.HarnessDetails) error {
harness.ESC10bHarness2.Setup(testContext)
return nil
}, func(harness integration.HarnessDetails, db graph.Database) {
operation := analysis.NewPostRelationshipOperation(context.Background(), db, "ADCS Post Process Test - ESC10b")

groupExpansions, enterpriseCertAuthorities, _, domains, cache, err := FetchADCSPrereqs(db)
require.Nil(t, err)

for _, domain := range domains {
innerDomain := domain

for _, enterpriseCA := range enterpriseCertAuthorities {
if cache.DoesCAChainProperlyToDomain(enterpriseCA, innerDomain) {
innerEnterpriseCA := enterpriseCA

operation.Operation.SubmitReader(func(ctx context.Context, tx graph.Transaction, outC chan<- analysis.CreatePostRelationshipJob) error {
if err := ad2.PostADCSESC10b(ctx, tx, outC, groupExpansions, innerEnterpriseCA, innerDomain, cache); err != nil {
t.Logf("failed post processing for %s: %v", ad.ADCSESC10b.String(), err)
} else {
return nil
}

return nil
})
}
}
}
err = operation.Done()
require.Nil(t, err)

db.ReadTransaction(context.Background(), func(tx graph.Transaction) error {
if results, err := ops.FetchStartNodes(tx.Relationships().Filterf(func() graph.Criteria {
return query.Kind(query.Relationship(), ad.ADCSESC10b)
})); err != nil {
t.Fatalf("error fetching esc10b edges in integration test; %v", err)
} else {
require.Equal(t, 2, len(results))

require.True(t, results.Contains(harness.ESC10bHarness2.Computer5))
require.True(t, results.Contains(harness.ESC10bHarness2.User5))

}
return nil
})
})

testContext.DatabaseTestWithSetup(func(harness *integration.HarnessDetails) error {
harness.ESC10bHarnessECA.Setup(testContext)
return nil
}, func(harness integration.HarnessDetails, db graph.Database) {
operation := analysis.NewPostRelationshipOperation(context.Background(), db, "ADCS Post Process Test - ESC10b")

groupExpansions, enterpriseCertAuthorities, _, domains, cache, err := FetchADCSPrereqs(db)
require.Nil(t, err)

for _, domain := range domains {
innerDomain := domain

for _, enterpriseCA := range enterpriseCertAuthorities {
if cache.DoesCAChainProperlyToDomain(enterpriseCA, innerDomain) {
innerEnterpriseCA := enterpriseCA

operation.Operation.SubmitReader(func(ctx context.Context, tx graph.Transaction, outC chan<- analysis.CreatePostRelationshipJob) error {
if err := ad2.PostADCSESC10b(ctx, tx, outC, groupExpansions, innerEnterpriseCA, innerDomain, cache); err != nil {
t.Logf("failed post processing for %s: %v", ad.ADCSESC10b.String(), err)
} else {
return nil
}

return nil
})
}
}
}
err = operation.Done()
require.Nil(t, err)

db.ReadTransaction(context.Background(), func(tx graph.Transaction) error {
if results, err := ops.FetchStartNodes(tx.Relationships().Filterf(func() graph.Criteria {
return query.Kind(query.Relationship(), ad.ADCSESC10b)
})); err != nil {
t.Fatalf("error fetching esc10b edges in integration test; %v", err)
} else {
require.Equal(t, 1, len(results))

require.True(t, results.Contains(harness.ESC10bHarnessECA.Group1))

}
return nil
})
})

testContext.DatabaseTestWithSetup(func(harness *integration.HarnessDetails) error {
harness.ESC10bHarnessVictim.Setup(testContext)
return nil
}, func(harness integration.HarnessDetails, db graph.Database) {
operation := analysis.NewPostRelationshipOperation(context.Background(), db, "ADCS Post Process Test - ESC10b")

groupExpansions, enterpriseCertAuthorities, _, domains, cache, err := FetchADCSPrereqs(db)
require.Nil(t, err)

for _, domain := range domains {
innerDomain := domain

for _, enterpriseCA := range enterpriseCertAuthorities {
if cache.DoesCAChainProperlyToDomain(enterpriseCA, innerDomain) {
innerEnterpriseCA := enterpriseCA

operation.Operation.SubmitReader(func(ctx context.Context, tx graph.Transaction, outC chan<- analysis.CreatePostRelationshipJob) error {
if err := ad2.PostADCSESC10b(ctx, tx, outC, groupExpansions, innerEnterpriseCA, innerDomain, cache); err != nil {
t.Logf("failed post processing for %s: %v", ad.ADCSESC10b.String(), err)
} else {
return nil
}

return nil
})
}
}
}
err = operation.Done()
require.Nil(t, err)

db.ReadTransaction(context.Background(), func(tx graph.Transaction) error {
if results, err := ops.FetchStartNodes(tx.Relationships().Filterf(func() graph.Criteria {
return query.Kind(query.Relationship(), ad.ADCSESC10b)
})); err != nil {
t.Fatalf("error fetching esc10b edges in integration test; %v", err)
} else {
require.Equal(t, 2, len(results))

require.True(t, results.Contains(harness.ESC10bHarnessVictim.Group1))
require.True(t, results.Contains(harness.ESC10bHarnessVictim.Group2))

}
return nil
})
})
}
6 changes: 4 additions & 2 deletions cmd/api/src/api/middleware/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,9 @@ import (
"strings"
"time"

"github.com/specterops/bloodhound/src/ctx"

"github.com/gofrs/uuid"
"github.com/gorilla/mux"
"github.com/specterops/bloodhound/src/ctx"

"github.com/specterops/bloodhound/src/api"
"github.com/specterops/bloodhound/src/auth"
Expand Down Expand Up @@ -107,6 +106,7 @@ func PermissionsCheckAll(authorizer auth.Authorizer, permissions ...model.Permis
if bhCtx := ctx.FromRequest(request); !bhCtx.AuthCtx.Authenticated() {
api.WriteErrorResponse(request.Context(), api.BuildErrorResponse(http.StatusUnauthorized, "not authenticated", request), response)
} else if !authorizer.AllowsAllPermissions(bhCtx.AuthCtx, permissions) {
authorizer.AuditLogUnauthorizedAccess(request)
api.WriteErrorResponse(request.Context(), api.BuildErrorResponse(http.StatusForbidden, "not authorized", request), response)
} else {
next.ServeHTTP(response, request)
Expand All @@ -123,6 +123,7 @@ func PermissionsCheckAtLeastOne(authorizer auth.Authorizer, permissions ...model
if bhCtx := ctx.FromRequest(request); !bhCtx.AuthCtx.Authenticated() {
api.WriteErrorResponse(request.Context(), api.BuildErrorResponse(http.StatusUnauthorized, "not authenticated", request), response)
} else if !authorizer.AllowsAtLeastOnePermission(bhCtx.AuthCtx, permissions) {
authorizer.AuditLogUnauthorizedAccess(request)
api.WriteErrorResponse(request.Context(), api.BuildErrorResponse(http.StatusForbidden, "not authorized", request), response)
} else {
next.ServeHTTP(response, request)
Expand Down Expand Up @@ -188,6 +189,7 @@ func AuthorizeAuthManagementAccess(permissions auth.PermissionSet, authorizer au
}

if !authorized {
authorizer.AuditLogUnauthorizedAccess(request)
api.WriteErrorResponse(request.Context(), api.BuildErrorResponse(http.StatusUnauthorized, fmt.Sprintf("not authorized for %s", userID), request), response)
} else {
next.ServeHTTP(response, request)
Expand Down
Loading

0 comments on commit 89f313f

Please sign in to comment.