Skip to content

feat: add support for Federated identity credentials: BED-7398#2453

Open
rvazarkar wants to merge 24 commits intomainfrom
federated_identity_credentials
Open

feat: add support for Federated identity credentials: BED-7398#2453
rvazarkar wants to merge 24 commits intomainfrom
federated_identity_credentials

Conversation

@rvazarkar
Copy link
Contributor

@rvazarkar rvazarkar commented Mar 3, 2026

Description

Adds support for Federated Identity Credentials and the AZAuthenticatesTo edge from research
image

image image

Motivation and Context

https://specterops.atlassian.net/browse/BED-7398

How Has This Been Tested?

Local ingest testing using SpecterDev data, unit testing for ingest
Manual UI testing

Screenshots (optional):

Types of changes

  • New feature (non-breaking change which adds functionality)

Checklist:

Summary by CodeRabbit

Release Notes

New Features

  • Added Azure Federated Identity Credentials as a new asset type to support authentication scenarios
  • Introduced AZAuthenticatesTo relationship to model authentication flows between credentials and applications
  • Added Issuer, Subject, and Audiences properties for enhanced credential attributes

Documentation

  • Added comprehensive help documentation for the new AZAuthenticatesTo relationship, including abuse scenarios and opsec guidance

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 3, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR introduces support for Azure Federated Identity Credentials as a new node type and adds the AZAuthenticatesTo relationship. Changes span database schema migrations, Go service converters, schema definitions, UI help components, icon mappings, test fixtures, and an API schema update.

Changes

Cohort / File(s) Summary
Database Schema
cmd/api/src/database/migration/extensions/az_graph_schema.sql
Added node kind AZFederatedIdentityCredential and relationship kind AZAuthenticatesTo with schema metadata (display name, styling) and upsert sequences.
Go Service Converters
cmd/api/src/services/graphify/azure_convertors.go
Added convertAzureAppFIC function to handle marshaling and conversion of Federated Identity Credential data into nodes and relationships, with error handling for wrapper and inner FIC data.
Go Schema Definitions
packages/go/graphschema/azure/azure.go, packages/go/graphschema/common/common.go
Added FederatedIdentityCredential node kind and AZAuthenticatesTo relationship kind; added Issuer, Subject, Audiences properties with parsing and display logic; updated Relationships and NodeKinds exports.
Go Models & Converters
packages/go/ein/azure.go, packages/go/ein/azure_test.go
Added ConvertAppFederatedIdentityCredential function to construct IngestibleNode and IngestibleRelationship; refactored ConvertAzureUser for safer LastSuccessfulSignInDateTime handling; added corresponding unit test.
CUE Configuration
packages/cue/bh/azure/azure.cue
Added FederatedIdentityCredential Kind and AZAuthenticatesTo relationship Kind; added Issuer, Subject, Audiences string enums and properties.
UI Help Components
packages/javascript/bh-shared-ui/src/components/HelpTexts/AZAuthenticatesTo/*
Added General, Abuse, Opsec, References React components and AZAuthenticatesTo aggregator module; updated HelpTexts index to register new components.
UI Schema & Icons
packages/javascript/bh-shared-ui/src/graphSchema.ts, packages/javascript/bh-shared-ui/src/utils/icons.ts, packages/go/schemagen/generator/sql.go
Added FederatedIdentityCredential to AzureNodeKind and mapped in display components; added AZAuthenticatesTo to relationship kinds and pathfinding edges; added icon mapping (faKey, #FFEE8C) for FederatedIdentityCredential across UI and schema generator.
Test Fixtures
cmd/api/src/services/graphify/fixtures/AzureFederatedIdentityCredentials/...
Added raw, ingested, and analyzed JSON fixtures for integration testing with sample AZFederatedIdentityCredential nodes, properties, and AZAuthenticatesTo relationships.
Integration Tests
cmd/api/src/services/graphify/analysis_integration_test.go
Added TestFederatedIdentityCredentialAnalysis integration test following existing test patterns.
Dependencies & API Schema
go.mod, packages/go/openapi/doc/openapi.json
Updated azurehound dependency from v2.10.0 to v2.10.1-0.20260310183647-04f79abb0ba0; updated OpenAPI client-type enum from "opengraph_collector_platform" to "ogcollector".

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~28 minutes

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.68% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive Pull request description covers main sections but has incomplete checklist items regarding documentation updates and test confirmations. Complete the checklist by confirming that Open API docs and code comments (GoDocs/JSDocs) have been updated, and verify that all new and existing tests have passed.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: adding support for Federated Identity Credentials with an associated Jira ticket reference.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch federated_identity_credentials

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai bot added enhancement New feature or request user interface A pull request containing changes affecting the UI code. labels Mar 3, 2026
@rvazarkar rvazarkar self-assigned this Mar 3, 2026
@coderabbitai coderabbitai bot added api A pull request containing changes affecting the API code. dbmigration labels Mar 3, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
packages/javascript/bh-shared-ui/src/components/HelpTexts/AZAuthenticatesTo/References.tsx (1)

22-27: Use descriptive link text instead of rendering the full URL.

The current raw URL is hard to scan and brittle for future text updates. Prefer readable anchor text while keeping the same href.

♻️ Proposed refactor
             <a
                 target='_blank'
                 rel='noopener noreferrer'
                 href='https://medium.com/@zahmed333/understanding-federated-identity-credentials-simplifying-secure-access-6b67fa79475b'>
-                https://medium.com/@zahmed333/understanding-federated-identity-credentials-simplifying-secure-access-6b67fa79475b
+                Understanding Federated Identity Credentials
             </a>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/javascript/bh-shared-ui/src/components/HelpTexts/AZAuthenticatesTo/References.tsx`
around lines 22 - 27, Replace the raw URL anchor in the References component
with descriptive link text: locate the <a> element in References.tsx that
currently renders the full Medium URL and change its children from the long URL
string to a concise, accessible label (e.g., "Understanding Federated Identity
Credentials (Medium)") while keeping the href, target, and rel attributes
unchanged; ensure the anchor text is meaningful and preserves the original href
for correct navigation.
packages/javascript/bh-shared-ui/src/components/HelpTexts/AZAuthenticatesTo/AZAuthenticatesTo.tsx (1)

22-27: Lock the aggregator object shape with as const.

This helps preserve literal keys and prevents accidental mutation of the mapping.

♻️ Proposed refactor
 const AZAuthenticatesTo = {
     general: General,
     abuse: Abuse,
     opsec: Opsec,
     references: References,
-};
+} as const;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/javascript/bh-shared-ui/src/components/HelpTexts/AZAuthenticatesTo/AZAuthenticatesTo.tsx`
around lines 22 - 27, The AZAuthenticatesTo object currently allows its shape
and keys to be widened or mutated; update the declaration of AZAuthenticatesTo
to use a const assertion (append "as const") so TypeScript preserves the literal
keys and makes the mapping readonly, e.g., apply the assertion to the
AZAuthenticatesTo initializer so the object shape is locked and cannot be
altered at compile time; ensure any usages expecting mutable behavior are
adjusted to accept the readonly/literal type if needed.
packages/javascript/bh-shared-ui/src/components/HelpTexts/AZAuthenticatesTo/General.tsx (1)

21-29: Consider semantic paragraph splitting instead of <br />.

This reads as two separate thoughts; two <p> blocks are a bit cleaner for structure and accessibility.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/javascript/bh-shared-ui/src/components/HelpTexts/AZAuthenticatesTo/General.tsx`
around lines 21 - 29, The paragraph in the JSX using <p
className='edge-accordion-body2'> contains two distinct thoughts separated by a
<br />; split this into two semantic <p> elements (both using the same className
if styling should remain) instead of the <br /> to improve structure and
accessibility—update the JSX in General.tsx where the paragraph is rendered to
replace the single <p> with two <p className='edge-accordion-body2'> blocks
containing the respective sentences.
cmd/api/src/services/graphify/azure_convertors.go (1)

210-231: Typo in variable name: "federatedIdentifyCredential" should be "federatedIdentityCredential".

The variable name has a typo on line 220 (Identify instead of Identity), which affects readability and consistency with the type name.

✏️ Suggested fix
 		for _, rawFIC := range data.FICs {
 			var (
-				federatedIdentifyCredential models.FICData
+				federatedIdentityCredential models.FICData
 			)
-			if err := json.Unmarshal(rawFIC.FIC, &federatedIdentifyCredential); err != nil {
+			if err := json.Unmarshal(rawFIC.FIC, &federatedIdentityCredential); err != nil {
 				slog.Error(fmt.Sprintf(SerialError, "app federated identity credential data", err))
 			} else {
-				node, rel := ein.ConvertAppFederatedIdentityCredential(federatedIdentifyCredential, rawFIC.AppId)
+				node, rel := ein.ConvertAppFederatedIdentityCredential(federatedIdentityCredential, rawFIC.AppId)
 				converted.NodeProps = append(converted.NodeProps, node)
 				converted.RelProps = append(converted.RelProps, rel)
 			}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/api/src/services/graphify/azure_convertors.go` around lines 210 - 231, In
convertAzureAppFIC, rename the misspelled local variable
federatedIdentifyCredential to federatedIdentityCredential for consistency with
the models.FICData type and readability; update all uses of that identifier (the
json.Unmarshal target and the argument passed to
ein.ConvertAppFederatedIdentityCredential) so the variable name matches exactly
and compile cleanly, leaving the surrounding error handling, rawFIC, convert
call, and appending to converted.NodeProps/converted.RelProps unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/go/ein/azure.go`:
- Around line 241-270: The relationship endpoints in
ConvertAppFederatedIdentityCredential are reversed: NewIngestibleRelationship
currently sets the FIC as source and the App as target, but the App should be
the source for an azure.Owns relation. Fix by swapping the two
IngestibleEndpoint arguments in the NewIngestibleRelationship call so the App
endpoint (Kind: azure.App, Value: strings.ToUpper(appID)) is the first/source
endpoint and the FIC endpoint (Kind: azure.FederatedIdentityCredential, Value:
strings.ToUpper(federatedIdentityCredential.ID)) is the second/target endpoint,
keeping RelType: azure.Owns (consistent with ConvertAzureOwnerToRel).

---

Nitpick comments:
In `@cmd/api/src/services/graphify/azure_convertors.go`:
- Around line 210-231: In convertAzureAppFIC, rename the misspelled local
variable federatedIdentifyCredential to federatedIdentityCredential for
consistency with the models.FICData type and readability; update all uses of
that identifier (the json.Unmarshal target and the argument passed to
ein.ConvertAppFederatedIdentityCredential) so the variable name matches exactly
and compile cleanly, leaving the surrounding error handling, rawFIC, convert
call, and appending to converted.NodeProps/converted.RelProps unchanged.

In
`@packages/javascript/bh-shared-ui/src/components/HelpTexts/AZAuthenticatesTo/AZAuthenticatesTo.tsx`:
- Around line 22-27: The AZAuthenticatesTo object currently allows its shape and
keys to be widened or mutated; update the declaration of AZAuthenticatesTo to
use a const assertion (append "as const") so TypeScript preserves the literal
keys and makes the mapping readonly, e.g., apply the assertion to the
AZAuthenticatesTo initializer so the object shape is locked and cannot be
altered at compile time; ensure any usages expecting mutable behavior are
adjusted to accept the readonly/literal type if needed.

In
`@packages/javascript/bh-shared-ui/src/components/HelpTexts/AZAuthenticatesTo/General.tsx`:
- Around line 21-29: The paragraph in the JSX using <p
className='edge-accordion-body2'> contains two distinct thoughts separated by a
<br />; split this into two semantic <p> elements (both using the same className
if styling should remain) instead of the <br /> to improve structure and
accessibility—update the JSX in General.tsx where the paragraph is rendered to
replace the single <p> with two <p className='edge-accordion-body2'> blocks
containing the respective sentences.

In
`@packages/javascript/bh-shared-ui/src/components/HelpTexts/AZAuthenticatesTo/References.tsx`:
- Around line 22-27: Replace the raw URL anchor in the References component with
descriptive link text: locate the <a> element in References.tsx that currently
renders the full Medium URL and change its children from the long URL string to
a concise, accessible label (e.g., "Understanding Federated Identity Credentials
(Medium)") while keeping the href, target, and rel attributes unchanged; ensure
the anchor text is meaningful and preserves the original href for correct
navigation.

ℹ️ Review info

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 821982f and 82499c0.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (20)
  • cmd/api/src/api/v2/azure.go
  • cmd/api/src/database/migration/extensions/ad_graph_schema.sql
  • cmd/api/src/database/migration/extensions/az_graph_schema.sql
  • cmd/api/src/services/graphify/azure_convertors.go
  • go.mod
  • packages/cue/bh/azure/azure.cue
  • packages/go/ein/azure.go
  • packages/go/graphschema/azure/azure.go
  • packages/go/graphschema/common/common.go
  • packages/go/schemagen/generator/sql.go
  • packages/javascript/bh-shared-ui/src/components/HelpTexts/AZAuthenticatesTo/AZAuthenticatesTo.tsx
  • packages/javascript/bh-shared-ui/src/components/HelpTexts/AZAuthenticatesTo/Abuse.tsx
  • packages/javascript/bh-shared-ui/src/components/HelpTexts/AZAuthenticatesTo/General.tsx
  • packages/javascript/bh-shared-ui/src/components/HelpTexts/AZAuthenticatesTo/Opsec.tsx
  • packages/javascript/bh-shared-ui/src/components/HelpTexts/AZAuthenticatesTo/References.tsx
  • packages/javascript/bh-shared-ui/src/components/HelpTexts/index.tsx
  • packages/javascript/bh-shared-ui/src/graphSchema.ts
  • packages/javascript/bh-shared-ui/src/utils/icons.ts
  • packages/javascript/bh-shared-ui/src/views/UserProfile/UserProfile.test.tsx
  • packages/javascript/bh-shared-ui/src/views/Users/UserActionsMenu.test.tsx

# Conflicts:
#	packages/go/graphschema/azure/azure.go
#	packages/go/graphschema/common/common.go
test:  add test for new ein function
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
packages/go/ein/azure.go (1)

241-270: Hoist and name local initializations more explicitly in this converter.

At Line 242 and Line 254, consider using a single var (...) block with richer names to align with repo Go style.

Proposed refactor
 func ConvertAppFederatedIdentityCredential(federatedIdentityCredential models.FICData, appID string) (IngestibleNode, IngestibleRelationship) {
-	node := IngestibleNode{
+	var (
+		federatedIdentityCredentialNode = IngestibleNode{
 		ObjectID: strings.ToUpper(federatedIdentityCredential.ID),
 		PropertyMap: map[string]any{
 			common.Description.String(): federatedIdentityCredential.Description,
 			common.Name.String():        federatedIdentityCredential.Name,
 			azure.Issuer.String():       federatedIdentityCredential.Issuer,
 			azure.Audiences.String():    federatedIdentityCredential.Audiences,
 			azure.Subject.String():      federatedIdentityCredential.Subject,
 		},
 		Labels: []graph.Kind{azure.FederatedIdentityCredential, azure.Entity},
-	}
+		}
 
-	rel := NewIngestibleRelationship(
+		authenticatesToRelationship = NewIngestibleRelationship(
 		IngestibleEndpoint{
 			Value: strings.ToUpper(federatedIdentityCredential.ID),
 			Kind:  azure.FederatedIdentityCredential,
 		},
 		IngestibleEndpoint{
 			Kind:  azure.App,
 			Value: strings.ToUpper(appID),
 		},
 		IngestibleRel{
 			RelProps: map[string]any{},
 			RelType:  azure.AZAuthenticatesTo,
 		},
-	)
+		)
+	)
 
-	return node, rel
+	return federatedIdentityCredentialNode, authenticatesToRelationship
 }
As per coding guidelines, "Group variable initializations in a `var ( ... )` block and hoist them to the top of the function when possible" and "Prefer rich variable names, for example: `databaseInterface` instead of `di` or `dbi`".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/go/ein/azure.go` around lines 241 - 270, The
ConvertAppFederatedIdentityCredential function currently declares local
composites inline (node and rel); hoist these initializations into a var (...)
block at the top of the function and give them clearer names (e.g.,
federatedIdentityNode for the IngestibleNode and authenticatesRel for the
IngestibleRelationship) to follow repo style; build federatedIdentityNode using
fields from federatedIdentityCredential and appID, then construct
authenticatesRel via NewIngestibleRelationship and return those variables
instead of the inline literals.
packages/go/ein/azure_test.go (1)

61-80: Add assertions for base-kind labeling on the generated FIC node.

At Line 73 onward, this test validates relationship direction/type, but it should also assert that the node keeps both azure.FederatedIdentityCredential and azure.Entity labels to guard query compatibility.

Proposed test additions
 	node, rel := ein.ConvertAppFederatedIdentityCredential(testData, appID)
 	require.NotNil(t, node)
 	require.NotNil(t, rel)
+	require.Contains(t, node.Labels, azure.FederatedIdentityCredential)
+	require.Contains(t, node.Labels, azure.Entity)
 
 	require.Equal(t, rel.RelType, azure.AZAuthenticatesTo)
 	require.Equal(t, rel.Source.Value, strings.ToUpper(testData.ID))
 	require.Equal(t, rel.Target.Value, strings.ToUpper(appID))
Based on learnings, "In BloodHound, AD nodes are represented by a base kind ... and Azure nodes by az.Entity ... code that filters or queries graph nodes via KindIn uses the base kind to capture all inherited subkinds."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/go/ein/azure_test.go` around lines 61 - 80, The test
Test_ConvertAppFederatedIdentityCredential should also assert that the created
node includes both the specific and base-kind labels so queries that rely on the
base kind work; update the test after calling
ein.ConvertAppFederatedIdentityCredential to check that the returned node has
labels for azure.FederatedIdentityCredential and azure.Entity (i.e., ensure the
node's label set contains both identifiers) in addition to the existing
relationship assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/go/ein/azure_test.go`:
- Around line 61-80: The test Test_ConvertAppFederatedIdentityCredential should
also assert that the created node includes both the specific and base-kind
labels so queries that rely on the base kind work; update the test after calling
ein.ConvertAppFederatedIdentityCredential to check that the returned node has
labels for azure.FederatedIdentityCredential and azure.Entity (i.e., ensure the
node's label set contains both identifiers) in addition to the existing
relationship assertions.

In `@packages/go/ein/azure.go`:
- Around line 241-270: The ConvertAppFederatedIdentityCredential function
currently declares local composites inline (node and rel); hoist these
initializations into a var (...) block at the top of the function and give them
clearer names (e.g., federatedIdentityNode for the IngestibleNode and
authenticatesRel for the IngestibleRelationship) to follow repo style; build
federatedIdentityNode using fields from federatedIdentityCredential and appID,
then construct authenticatesRel via NewIngestibleRelationship and return those
variables instead of the inline literals.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: c5b5c7ed-a65f-4551-806a-8bb287373f0a

📥 Commits

Reviewing files that changed from the base of the PR and between 8debc38 and 1f30e84.

📒 Files selected for processing (2)
  • packages/go/ein/azure.go
  • packages/go/ein/azure_test.go

@rvazarkar rvazarkar changed the title draft: feat: add support for Federated identity credentials: BED-7398 feat: add support for Federated identity credentials: BED-7398 Mar 10, 2026
@rvazarkar rvazarkar marked this pull request as draft March 10, 2026 15:36
@rvazarkar rvazarkar marked this pull request as ready for review March 10, 2026 18:59
@bsheth711 bsheth711 self-requested a review March 11, 2026 21:10
Copy link
Contributor

@wes-mil wes-mil left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't fully understand the changes, but I also don't see anything obviously wrong and tests appear to cover

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api A pull request containing changes affecting the API code. dbmigration enhancement New feature or request user interface A pull request containing changes affecting the UI code.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants