Skip to content

Commit a9be8be

Browse files
authored
Merge 9a50fdb into 371d2d3
2 parents 371d2d3 + 9a50fdb commit a9be8be

13 files changed

Lines changed: 1478 additions & 1065 deletions

.github/workflows/keyfactor-bootstrap-workflow.yml renamed to .github/workflows/keyfactor-starter-workflow.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ on:
1111

1212
jobs:
1313
call-starter-workflow:
14-
uses: keyfactor/actions/.github/workflows/starter.yml@v3
14+
uses: keyfactor/actions/.github/workflows/starter.yml@v3
1515
secrets:
1616
token: ${{ secrets.V2BUILDTOKEN}}
1717
APPROVE_README_PUSH: ${{ secrets.APPROVE_README_PUSH}}

AzureAppRegistration.sln

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
3-
#
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.13.35931.197 d17.13
5+
MinimumVisualStudioVersion = 10.0.40219.1
46
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureEnterpriseApplicationOrchestrator", "AzureEnterpriseApplicationOrchestrator\AzureEnterpriseApplicationOrchestrator.csproj", "{51A6B345-EFCF-4B84-B863-447B72E8E381}"
57
EndProject
6-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureEnterpriseApplicationOrchestrator.Tests", "AzureEnterpriseApplicationOrchestrator.Tests\AzureEnterpriseApplicationOrchestrator.Tests.csproj", "{A4384A83-D08A-4447-B63D-D1E596A4A561}"
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureEnterpriseApplicationOrchestrator.Tests", "AzureEnterpriseApplicationOrchestrator.Tests\AzureEnterpriseApplicationOrchestrator.Tests.csproj", "{4A6C5ECE-9D2E-EDFA-1707-7CEB2949BF4D}"
79
EndProject
810
Global
911
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -15,13 +17,15 @@ Global
1517
{51A6B345-EFCF-4B84-B863-447B72E8E381}.Debug|Any CPU.Build.0 = Debug|Any CPU
1618
{51A6B345-EFCF-4B84-B863-447B72E8E381}.Release|Any CPU.ActiveCfg = Release|Any CPU
1719
{51A6B345-EFCF-4B84-B863-447B72E8E381}.Release|Any CPU.Build.0 = Release|Any CPU
18-
{CF3213FC-F053-4409-9FBA-55978319FB6D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19-
{CF3213FC-F053-4409-9FBA-55978319FB6D}.Debug|Any CPU.Build.0 = Debug|Any CPU
20-
{CF3213FC-F053-4409-9FBA-55978319FB6D}.Release|Any CPU.ActiveCfg = Release|Any CPU
21-
{CF3213FC-F053-4409-9FBA-55978319FB6D}.Release|Any CPU.Build.0 = Release|Any CPU
22-
{A4384A83-D08A-4447-B63D-D1E596A4A561}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23-
{A4384A83-D08A-4447-B63D-D1E596A4A561}.Debug|Any CPU.Build.0 = Debug|Any CPU
24-
{A4384A83-D08A-4447-B63D-D1E596A4A561}.Release|Any CPU.ActiveCfg = Release|Any CPU
25-
{A4384A83-D08A-4447-B63D-D1E596A4A561}.Release|Any CPU.Build.0 = Release|Any CPU
20+
{4A6C5ECE-9D2E-EDFA-1707-7CEB2949BF4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21+
{4A6C5ECE-9D2E-EDFA-1707-7CEB2949BF4D}.Debug|Any CPU.Build.0 = Debug|Any CPU
22+
{4A6C5ECE-9D2E-EDFA-1707-7CEB2949BF4D}.Release|Any CPU.ActiveCfg = Release|Any CPU
23+
{4A6C5ECE-9D2E-EDFA-1707-7CEB2949BF4D}.Release|Any CPU.Build.0 = Release|Any CPU
24+
EndGlobalSection
25+
GlobalSection(SolutionProperties) = preSolution
26+
HideSolutionNode = FALSE
27+
EndGlobalSection
28+
GlobalSection(ExtensibilityGlobals) = postSolution
29+
SolutionGuid = {DA3FE492-51E1-450E-938C-259942704D0D}
2630
EndGlobalSection
2731
EndGlobal

AzureEnterpriseApplicationOrchestrator/AzureEnterpriseApplicationOrchestrator.csproj

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>net6.0</TargetFramework>
5-
<ImplicitUsings>disable</ImplicitUsings>
6-
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
7-
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
8-
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
9-
<RootNamespace>AzureEnterpriseApplicationOrchestrator</RootNamespace>
4+
<AppendTargetFrameworkToOutputPath>true</AppendTargetFrameworkToOutputPath>
5+
<TargetFrameworks>net6.0;net8.0</TargetFrameworks>
6+
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
7+
<ImplicitUsings>disable</ImplicitUsings>
108
</PropertyGroup>
119

1210
<ItemGroup>

AzureEnterpriseApplicationOrchestrator/Client/GraphClient.cs

Lines changed: 149 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -485,30 +485,60 @@ public OperationResult<IEnumerable<string>> DiscoverApplicationObjectIds()
485485
List<string> oids = new();
486486
OperationResult<IEnumerable<string>> result = new(oids);
487487

488-
_logger.LogDebug($"Retrieving application registrations for tenant ID \"{_tenantId}\"");
489-
ApplicationCollectionResponse apps;
488+
_logger.LogDebug($"Retrieving Applications for tenant ID \"{_tenantId}\"");
489+
List<Application> allApplications = new List<Application>();
490490
try
491491
{
492-
apps = _graphClient.Applications.GetAsync((requestConfiguration) =>
492+
var spsResponse = _graphClient.Applications.GetAsync(requestConfiguration =>
493+
{
494+
requestConfiguration.QueryParameters.Top = 500;
495+
}).Result;
496+
497+
if (spsResponse?.Value == null)
498+
{
499+
_logger.LogWarning("No Applications found.");
500+
return result;
501+
}
502+
503+
// Create the PageIterator to handle pagination
504+
var pageIterator = PageIterator<Application, ApplicationCollectionResponse>
505+
.CreatePageIterator(
506+
_graphClient,
507+
spsResponse,
508+
// Callback executed for each Application in the collection
509+
(application) =>
493510
{
494-
requestConfiguration.QueryParameters.Top = 999;
495-
}).Result;
511+
// Add each application to the list
512+
allApplications.Add(application);
513+
return true; // Continue to the next item
514+
},
515+
// Configure subsequent page requests
516+
(request) =>
517+
{
518+
_logger.LogDebug("Fetching the next page of applications...");
519+
return request;
520+
});
521+
522+
// Execute the pagination
523+
pageIterator.IterateAsync().Wait();
524+
525+
_logger.LogInformation($"Successfully retrieved {allApplications.Count} applications.");
496526
}
497527
catch (AggregateException e)
498528
{
499529
_logger.LogError($"Unable to retrieve application registrations for tenant ID \"{_tenantId}\": {e}");
500530
throw;
501531
}
502532

503-
if (apps?.Value == null || apps.Value.Count == 0)
533+
if (allApplications.Count == 0)
504534
{
505-
_logger.LogWarning($"No application registrations found for tenant ID \"{_tenantId}\"");
535+
_logger.LogWarning($"No Applications found for tenant ID \"{_tenantId}\"");
506536
return result;
507537
}
508538

509-
foreach (Application app in apps.Value)
539+
foreach (Application app in allApplications)
510540
{
511-
_logger.LogDebug($"Found application \"{app.DisplayName}\" ({app.Id})");
541+
_logger.LogDebug($"Found Application \"{app.DisplayName}\" ({app.Id})");
512542

513543
if (string.IsNullOrEmpty(app.Id))
514544
{
@@ -529,27 +559,57 @@ public OperationResult<IEnumerable<string>> DiscoverServicePrincipalObjectIds()
529559
OperationResult<IEnumerable<string>> result = new(oids);
530560

531561
_logger.LogDebug($"Retrieving Service Principals for tenant ID \"{_tenantId}\"");
532-
ServicePrincipalCollectionResponse sps;
562+
List<ServicePrincipal> allServicePrincipals = new List<ServicePrincipal>();
533563
try
534564
{
535-
sps = _graphClient.ServicePrincipals.GetAsync((requestConfiguration) =>
565+
var spsResponse = _graphClient.ServicePrincipals.GetAsync(requestConfiguration =>
536566
{
537-
requestConfiguration.QueryParameters.Top = 999;
567+
requestConfiguration.QueryParameters.Top = 500;
538568
}).Result;
569+
570+
if (spsResponse?.Value == null)
571+
{
572+
_logger.LogWarning("No service principals found.");
573+
return result;
574+
}
575+
576+
// Create the PageIterator to handle pagination
577+
var pageIterator = PageIterator<ServicePrincipal, ServicePrincipalCollectionResponse>
578+
.CreatePageIterator(
579+
_graphClient,
580+
spsResponse,
581+
// Callback executed for each Service Principal in the collection
582+
(servicePrincipal) =>
583+
{
584+
// Add each service principal to the list
585+
allServicePrincipals.Add(servicePrincipal);
586+
return true; // Continue to the next item
587+
},
588+
// Configure subsequent page requests
589+
(request) =>
590+
{
591+
_logger.LogDebug("Fetching the next page of service principals...");
592+
return request;
593+
});
594+
595+
// Execute the pagination
596+
pageIterator.IterateAsync().Wait();
597+
598+
_logger.LogInformation($"Successfully retrieved {allServicePrincipals.Count} service principals.");
539599
}
540600
catch (AggregateException e)
541601
{
542602
_logger.LogError($"Unable to retrieve Service Principals for tenant ID \"{_tenantId}\": {e}");
543603
throw;
544604
}
545605

546-
if (sps?.Value == null || sps.Value.Count == 0)
606+
if (allServicePrincipals.Count == 0)
547607
{
548608
_logger.LogWarning($"No Service Principals found for tenant ID \"{_tenantId}\"");
549609
return result;
550610
}
551611

552-
foreach (ServicePrincipal sp in sps.Value)
612+
foreach (ServicePrincipal sp in allServicePrincipals)
553613
{
554614
_logger.LogDebug($"Found SP \"{sp.DisplayName}\" ({sp.Id})");
555615

@@ -571,30 +631,60 @@ public OperationResult<IEnumerable<string>> DiscoverApplicationApplicationIds()
571631
List<string> appIds = new();
572632
OperationResult<IEnumerable<string>> result = new(appIds);
573633

574-
_logger.LogDebug($"Retrieving application registrations for tenant ID \"{_tenantId}\"");
575-
ApplicationCollectionResponse apps;
634+
_logger.LogDebug($"Retrieving Applications in tenant ID \"{_tenantId}\"");
635+
List<Application> allApplications = new List<Application>();
576636
try
577637
{
578-
apps = _graphClient.Applications.GetAsync((requestConfiguration) =>
638+
var spsResponse = _graphClient.Applications.GetAsync(requestConfiguration =>
639+
{
640+
requestConfiguration.QueryParameters.Top = 500;
641+
}).Result;
642+
643+
if (spsResponse?.Value == null)
644+
{
645+
_logger.LogWarning("No applications found.");
646+
return result;
647+
}
648+
649+
// Create the PageIterator to handle pagination
650+
var pageIterator = PageIterator<Application, ApplicationCollectionResponse>
651+
.CreatePageIterator(
652+
_graphClient,
653+
spsResponse,
654+
// Callback executed for each Application in the collection
655+
(application) =>
579656
{
580-
requestConfiguration.QueryParameters.Top = 999;
581-
}).Result;
657+
// Add each application to the list
658+
allApplications.Add(application);
659+
return true; // Continue to the next item
660+
},
661+
// Configure subsequent page requests
662+
(request) =>
663+
{
664+
_logger.LogDebug("Fetching the next page of applications...");
665+
return request;
666+
});
667+
668+
// Execute the pagination
669+
pageIterator.IterateAsync().Wait();
670+
671+
_logger.LogInformation($"Successfully retrieved {allApplications.Count} applications.");
582672
}
583673
catch (AggregateException e)
584674
{
585-
_logger.LogError($"Unable to retrieve application registrations for tenant ID \"{_tenantId}\": {e}");
675+
_logger.LogError($"Unable to retrieve Applications for tenant ID \"{_tenantId}\": {e}");
586676
throw;
587677
}
588678

589-
if (apps?.Value == null || apps.Value.Count == 0)
679+
if (allApplications.Count == 0)
590680
{
591-
_logger.LogWarning($"No application registrations found for tenant ID \"{_tenantId}\"");
681+
_logger.LogWarning($"No Applications found for tenant ID \"{_tenantId}\"");
592682
return result;
593683
}
594684

595-
foreach (Application app in apps.Value)
685+
foreach (Application app in allApplications)
596686
{
597-
_logger.LogDebug($"Found application \"{app.DisplayName}\" ({app.Id})");
687+
_logger.LogDebug($"Found Application \"{app.DisplayName}\" ({app.Id})");
598688

599689
if (string.IsNullOrEmpty(app.AppId))
600690
{
@@ -615,27 +705,57 @@ public OperationResult<IEnumerable<string>> DiscoverServicePrincipalApplicationI
615705
OperationResult<IEnumerable<string>> result = new(appIds);
616706

617707
_logger.LogDebug($"Retrieving Service Principals for tenant ID \"{_tenantId}\"");
618-
ServicePrincipalCollectionResponse sps;
708+
List<ServicePrincipal> allServicePrincipals = new List<ServicePrincipal>();
619709
try
620710
{
621-
sps = _graphClient.ServicePrincipals.GetAsync((requestConfiguration) =>
711+
var spsResponse = _graphClient.ServicePrincipals.GetAsync(requestConfiguration =>
622712
{
623-
requestConfiguration.QueryParameters.Top = 999;
713+
requestConfiguration.QueryParameters.Top = 500;
624714
}).Result;
715+
716+
if (spsResponse?.Value == null)
717+
{
718+
_logger.LogWarning("No service principals found.");
719+
return result;
720+
}
721+
722+
// Create the PageIterator to handle pagination
723+
var pageIterator = PageIterator<ServicePrincipal, ServicePrincipalCollectionResponse>
724+
.CreatePageIterator(
725+
_graphClient,
726+
spsResponse,
727+
// Callback executed for each Service Principal in the collection
728+
(servicePrincipal) =>
729+
{
730+
// Add each service principal to the list
731+
allServicePrincipals.Add(servicePrincipal);
732+
return true; // Continue to the next item
733+
},
734+
// Configure subsequent page requests
735+
(request) =>
736+
{
737+
_logger.LogDebug("Fetching the next page of service principals...");
738+
return request;
739+
});
740+
741+
// Execute the pagination
742+
pageIterator.IterateAsync().Wait();
743+
744+
_logger.LogInformation($"Successfully retrieved {allServicePrincipals.Count} service principals.");
625745
}
626746
catch (AggregateException e)
627747
{
628748
_logger.LogError($"Unable to retrieve Service Principals for tenant ID \"{_tenantId}\": {e}");
629749
throw;
630750
}
631751

632-
if (sps?.Value == null || sps.Value.Count == 0)
752+
if (allServicePrincipals.Count == 0)
633753
{
634754
_logger.LogWarning($"No Service Principals found for tenant ID \"{_tenantId}\"");
635755
return result;
636756
}
637757

638-
foreach (ServicePrincipal sp in sps.Value)
758+
foreach (ServicePrincipal sp in allServicePrincipals)
639759
{
640760
_logger.LogDebug($"Found SP \"{sp.DisplayName}\" ({sp.Id})");
641761

CHANGELOG.md

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,29 @@
1-
- 1.0.1
1+
- 4.1.0
2+
- Paginate discovery method to download all available App Registrations and Enterprise Applications.
3+
- Fix DefineDiscoveredStores.ps1 to paginate Certificate Stores that come back from Command.
4+
- Add .net6/.net8 dual build
5+
6+
- 4.0.0
7+
- Depricate AzureApp and AzureSP in favor of AzureApp2 and AzureSP2 that interpret the Store Path field as the Object ID instead of App ID.
8+
- Discovery job modified to return available Certificate Stores with Store Path in the format `<ID GUID> (<Friendly Name>)`.
9+
- Before other jobs operate on Certificate Stores, the contents after the ID GUID will be truncated, maintaining backward compatibility.- 1.0.1
210
- First production release
311

4-
- 2.0.0
5-
- Properly report Private Key existence in Inventory job for both AzureSP and AzureApp.
6-
- Remove Private Key handling from AzureApp Certificate Store Type
12+
- 3.2.0
13+
- chore(docs): Upgrade GitHub Actions to use Bootstrap Workflow v3 to support Doctool
714

8-
- 3.0.0
9-
- Implement client certificate authentication as a secondary authentication method to Microsoft Graph API
15+
- 3.1.1
16+
- fix(deps): Revert main Azure App Registration and Enterprise Application Orchestrator extension .NET project to .NET 6 from .NET 8.
1017

1118
- 3.1.0
1219
- chore(deps): Upgrade .NET packages to their latest versions
1320

14-
- 3.1.1
15-
- fix(deps): Revert main Azure App Registration and Enterprise Application Orchestrator extension .NET project to .NET 6 from .NET 8.
16-
17-
- 3.2.0
18-
- chore(docs): Upgrade GitHub Actions to use Bootstrap Workflow v3 to support Doctool
21+
- 3.0.0
22+
- Implement client certificate authentication as a secondary authentication method to Microsoft Graph API
1923

20-
- 4.0.0
21-
- Depricate AzureApp and AzureSP in favor of AzureApp2 and AzureSP2 that interpret the Store Path field as the Object ID instead of App ID.
22-
- Discovery job modified to return available Certificate Stores with Store Path in the format `<ID GUID> (<Friendly Name>)`.
23-
- Before other jobs operate on Certificate Stores, the contents after the ID GUID will be truncated, maintaining backward compatibility.
24+
- 2.0.0
25+
- Properly report Private Key existence in Inventory job for both AzureSP and AzureApp.
26+
- Remove Private Key handling from AzureApp Certificate Store Type
2427

28+
- 1.0.1
29+
- First production release

0 commit comments

Comments
 (0)