From 2de919a53b85f1f8d6d268363eb73bce6e08a410 Mon Sep 17 00:00:00 2001 From: "Kartikeya Saxena (from Dev Box)" Date: Mon, 21 Oct 2024 17:36:34 +0530 Subject: [PATCH 01/11] initial commit --- .../MSFT_AADIdentityAPIConnector.psm1 | 566 ++++++++++++++++++ .../MSFT_AADIdentityAPIConnector.schema.mof | 18 + .../MSFT_AADIdentityAPIConnector/readme.md | 6 + .../settings.json | 25 + ...ft365DSC.AADIdentityAPIConnector.Tests.ps1 | 317 ++++++++++ Tests/Unit/Stubs/Microsoft365.psm1 | 287 +++++++++ 6 files changed, 1219 insertions(+) create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.psm1 create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.schema.mof create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/readme.md create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/settings.json create mode 100644 Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADIdentityAPIConnector.Tests.ps1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.psm1 new file mode 100644 index 0000000000..1c6c4bc75d --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.psm1 @@ -0,0 +1,566 @@ +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $TargetUrl, + + [Parameter(Mandatory = $true)] + [System.String] + $Id, + + [Parameter()] + [System.String] + $Username, + + [Parameter()] + [System.Management.Automation.PSCredential] + $Password, + + [Parameter()] + [System.Management.Automation.PSCredential] + $Pkcs12Value, + + #endregion + + [Parameter()] + [System.String] + [ValidateSet('Absent', 'Present')] + $Ensure = 'Present', + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ApplicationSecret, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [Switch] + $ManagedIdentity, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + try + { + $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` + -InboundParameters $PSBoundParameters + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace('MSFT_', '') + $CommandName = $MyInvocation.MyCommand + $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` + -CommandName $CommandName ` + -Parameters $PSBoundParameters + Add-M365DSCTelemetryEvent -Data $data + #endregion + + $nullResult = $PSBoundParameters + $nullResult.Ensure = 'Absent' + + $getValue = $null + #region resource generator code + $getValue = Get-MgBetaIdentityAPIConnector -IdentityApiConnectorId $Id -ErrorAction SilentlyContinue + + if ($null -eq $getValue) + { + Write-Verbose -Message "Could not find an Azure AD Identity A P I Connector with Id {$Id}" + + if (-not [System.String]::IsNullOrEmpty($DisplayName)) + { + $getValue = Get-MgBetaIdentityAPIConnector ` + -Filter "DisplayName eq '$DisplayName'" ` + -ErrorAction SilentlyContinue | Where-Object ` + -FilterScript { + $_.AdditionalProperties.'@odata.type' -eq "#microsoft.graph.IdentityApiConnector" + } + } + } + #endregion + if ($null -eq $getValue) + { + Write-Verbose -Message "Could not find an Azure AD Identity API Connector with DisplayName {$DisplayName}." + return $nullResult + } + $Id = $getValue.Id + Write-Verbose -Message "An Azure AD Identity API Connector with Id {$Id} and DisplayName {$DisplayName} was found" + + #region resource generator code + $complexAuthenticationConfiguration = @{} + + if($null -ne $getValue.AuthenticationConfiguration.AdditionalProperties.password) { + $securePassword = ConvertTo-SecureString $getValue.AuthenticationConfiguration.AdditionalProperties.password -AsPlainText -Force + + $Password = New-Object System.Management.Automation.PSCredential ('Password', $securePassword) + } + + if($null -ne $getValue.AuthenticationConfiguration.AdditionalProperties.pkcs12Value) { + $securePassword = ConvertTo-SecureString $getValue.AuthenticationConfiguration.AdditionalProperties.pkcs12Value -AsPlainText -Force + + $pkcs12Value = New-Object System.Management.Automation.PSCredential ('pkcs12Value', $securePassword) + } + #endregion + + $results = @{ + #region resource generator code + DisplayName = $getValue.DisplayName + TargetUrl = $getValue.TargetUrl + Id = $getValue.Id + Username = $getValue.AuthenticationConfiguration.AdditionalProperties.username + Password = $Password + Pkcs12Value = $pkcs12Value + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + ApplicationSecret = $ApplicationSecret + CertificateThumbprint = $CertificateThumbprint + ManagedIdentity = $ManagedIdentity.IsPresent + #endregion + } + + return [System.Collections.Hashtable] $results + } + catch + { + New-M365DSCLogEntry -Message 'Error retrieving data:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + + return $nullResult + } +} + +function Set-TargetResource +{ + [CmdletBinding()] + param + ( + #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $TargetUrl, + + [Parameter(Mandatory = $true)] + [System.String] + $Id, + + [Parameter()] + [System.String] + $Username, + + [Parameter()] + [System.Management.Automation.PSCredential] + $Password, + + [Parameter()] + [System.Management.Automation.PSCredential] + $Pkcs12Value, + + #endregion + + [Parameter()] + [System.String] + [ValidateSet('Absent', 'Present')] + $Ensure = 'Present', + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ApplicationSecret, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [Switch] + $ManagedIdentity, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace('MSFT_', '') + $CommandName = $MyInvocation.MyCommand + $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` + -CommandName $CommandName ` + -Parameters $PSBoundParameters + Add-M365DSCTelemetryEvent -Data $data + #endregion + + $currentInstance = Get-TargetResource @PSBoundParameters + + $BoundParameters = Remove-M365DSCAuthenticationParameter -BoundParameters $PSBoundParameters + + + if ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Absent') + { + Write-Verbose -Message "Creating an Azure AD Identity API Connector with DisplayName {$DisplayName}" + + $createParameters = ([Hashtable]$BoundParameters).Clone() + $createParameters = Rename-M365DSCCimInstanceParameter -Properties $createParameters + $createParameters.Remove('Id') | Out-Null + + $createParameters.Remove('Password') | Out-Null + $createParameters.Remove('Pkcs12Value') | Out-Null + + $createParameters.Add("AuthenticationConfiguration", @{ + '@odata.type' = "microsoft.graph.basicAuthentication" + "password" = $Password.GetNetworkCredential().Password + "username" = $Username + }) + + $createParameters.Add("@odata.type", "#microsoft.graph.IdentityApiConnector") + $policy = New-MgBetaIdentityAPIConnector -BodyParameter $createParameters + } + elseif ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Present') + { + Write-Verbose -Message "Updating the Azure AD Identity API Connector with Id {$($currentInstance.Id)}" + + $updateParameters = ([Hashtable]$BoundParameters).Clone() + $updateParameters = Rename-M365DSCCimInstanceParameter -Properties $updateParameters + + $updateParameters.Remove('Id') | Out-Null + + $updateParameters.Remove('Password') | Out-Null + $updateParameters.Remove('Pkcs12Value') | Out-Null + + $updateParameters.Add("AuthenticationConfiguration", @{ + '@odata.type' = "microsoft.graph.basicAuthentication" + "password" = $Password.GetNetworkCredential().Password + "username" = $Username + }) + + $UpdateParameters.Add("@odata.type", "#microsoft.graph.IdentityApiConnector") + Update-MgBetaIdentityAPIConnector ` + -IdentityApiConnectorId $currentInstance.Id ` + -BodyParameter $UpdateParameters + } + elseif ($Ensure -eq 'Absent' -and $currentInstance.Ensure -eq 'Present') + { + Write-Verbose -Message "Removing the Azure AD Identity API Connector with Id {$($currentInstance.Id)}" + Remove-MgBetaIdentityAPIConnector -IdentityApiConnectorId $currentInstance.Id + } +} + +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $TargetUrl, + + [Parameter(Mandatory = $true)] + [System.String] + $Id, + + [Parameter()] + [System.String] + $Username, + + [Parameter()] + [System.Management.Automation.PSCredential] + $Password, + + [Parameter()] + [System.Management.Automation.PSCredential] + $Pkcs12Value, + + #endregion + + [Parameter()] + [System.String] + [ValidateSet('Absent', 'Present')] + $Ensure = 'Present', + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ApplicationSecret, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [Switch] + $ManagedIdentity, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace('MSFT_', '') + $CommandName = $MyInvocation.MyCommand + $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` + -CommandName $CommandName ` + -Parameters $PSBoundParameters + Add-M365DSCTelemetryEvent -Data $data + #endregion + + Write-Verbose -Message "Testing configuration of the Azure AD Identity A P I Connector with Id {$Id} and DisplayName {$DisplayName}" + + $CurrentValues = Get-TargetResource @PSBoundParameters + $ValuesToCheck = ([Hashtable]$PSBoundParameters).clone() + + if ($CurrentValues.Ensure -ne $Ensure) + { + Write-Verbose -Message "Test-TargetResource returned $false" + return $false + } + $testResult = $true + + #Compare Cim instances + foreach ($key in $PSBoundParameters.Keys) + { + $source = $PSBoundParameters.$key + $target = $CurrentValues.$key + if ($null -ne $source -and $source.GetType().Name -like '*CimInstance*') + { + $testResult = Compare-M365DSCComplexObject ` + -Source ($source) ` + -Target ($target) + + if (-not $testResult) + { + break + } + + $ValuesToCheck.Remove($key) | Out-Null + } + } + + $ValuesToCheck.Remove('Id') | Out-Null + $ValuesToCheck.Remove('Password') | Out-Null + $ValuesToCheck.Remove('Pkcs12Value') | Out-Null + $ValuesToCheck = Remove-M365DSCAuthenticationParameter -BoundParameters $ValuesToCheck + + Write-Verbose -Message "Current Values: $(Convert-M365DscHashtableToString -Hashtable $CurrentValues)" + Write-Verbose -Message "Target Values: $(Convert-M365DscHashtableToString -Hashtable $ValuesToCheck)" + + if ($testResult) + { + $testResult = Test-M365DSCParameterState -CurrentValues $CurrentValues ` + -Source $($MyInvocation.MyCommand.Source) ` + -DesiredValues $PSBoundParameters ` + -ValuesToCheck $ValuesToCheck.Keys + } + + Write-Verbose -Message "Test-TargetResource returned $testResult" + + return $testResult +} + +function Export-TargetResource +{ + [CmdletBinding()] + [OutputType([System.String])] + param + ( + [Parameter()] + [System.String] + $Filter, + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ApplicationSecret, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [Switch] + $ManagedIdentity, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` + -InboundParameters $PSBoundParameters + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace('MSFT_', '') + $CommandName = $MyInvocation.MyCommand + $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` + -CommandName $CommandName ` + -Parameters $PSBoundParameters + Add-M365DSCTelemetryEvent -Data $data + #endregion + + try + { + #region resource generator code + [array]$getValue = Get-MgBetaIdentityAPIConnector ` + -Filter $Filter ` + -All ` + -ErrorAction Stop + #endregion + + $i = 1 + $dscContent = '' + if ($getValue.Length -eq 0) + { + Write-Host $Global:M365DSCEmojiGreenCheckMark + } + else + { + Write-Host "`r`n" -NoNewline + } + foreach ($config in $getValue) + { + $displayedKey = $config.Id + if (-not [String]::IsNullOrEmpty($config.displayName)) + { + $displayedKey = $config.displayName + } + elseif (-not [string]::IsNullOrEmpty($config.name)) + { + $displayedKey = $config.name + } + Write-Host " |---[$i/$($getValue.Count)] $displayedKey" -NoNewline + $params = @{ + Id = $config.Id + DisplayName = $config.DisplayName + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + ApplicationSecret = $ApplicationSecret + CertificateThumbprint = $CertificateThumbprint + ManagedIdentity = $ManagedIdentity.IsPresent + AccessTokens = $AccessTokens + } + + $Results = Get-TargetResource @Params + $Results.Password = "New-Object System.Management.Automation.PSCredential('Password', (ConvertTo-SecureString ((New-Guid).ToString()) -AsPlainText -Force));" + + $Results.Pkcs12Value = "New-Object System.Management.Automation.PSCredential('Pkcs12Value', (ConvertTo-SecureString ((New-Guid).ToString()) -AsPlainText -Force));" + + $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` + -Results $Results + + $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName ` + -ConnectionMode $ConnectionMode ` + -ModulePath $PSScriptRoot ` + -Results $Results ` + -Credential $Credential + + + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName 'Pkcs12Value' + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName 'Password' + + $dscContent += $currentDSCBlock + Save-M365DSCPartialExport -Content $currentDSCBlock ` + -FileName $Global:PartialExportFileName + $i++ + Write-Host $Global:M365DSCEmojiGreenCheckMark + } + return $dscContent + } + catch + { + Write-Host $Global:M365DSCEmojiRedX + + New-M365DSCLogEntry -Message 'Error during Export:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + + return '' + } +} + +Export-ModuleMember -Function *-TargetResource diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.schema.mof new file mode 100644 index 0000000000..7c359ad403 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.schema.mof @@ -0,0 +1,18 @@ +[ClassVersion("1.0.0.0"), FriendlyName("AADIdentityAPIConnector")] +class MSFT_AADIdentityAPIConnector : OMI_BaseResource +{ + [Required, Description("The name of the API connector.")] String DisplayName; + [Write, Description("The URL of the API endpoint to call.")] String TargetUrl; + [Key, Description("The unique identifier for an entity. Read-only.")] String Id; + [Write, Description("The username of the password")] String Username; + [Write, Description("The password of certificate/basic auth"), EmbeddedInstance("MSFT_Credential")] String Password; + [Write, Description("The Pkcs12Value of the certificate"), EmbeddedInstance("MSFT_Credential")] String Pkcs12Value; + [Write, Description("Present ensures the policy exists, absent ensures it is removed."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] string Ensure; + [Write, Description("Credentials of the Admin"), EmbeddedInstance("MSFT_Credential")] string Credential; + [Write, Description("Id of the Azure Active Directory application to authenticate with.")] String ApplicationId; + [Write, Description("Id of the Azure Active Directory tenant used for authentication.")] String TenantId; + [Write, Description("Secret of the Azure Active Directory tenant used for authentication."), EmbeddedInstance("MSFT_Credential")] String ApplicationSecret; + [Write, Description("Thumbprint of the Azure Active Directory application's authentication certificate to use for authentication.")] String CertificateThumbprint; + [Write, Description("Managed ID being used for authentication.")] Boolean ManagedIdentity; + [Write, Description("Access token used for authentication.")] String AccessTokens[]; +}; diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/readme.md b/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/readme.md new file mode 100644 index 0000000000..cfafce7110 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/readme.md @@ -0,0 +1,6 @@ + +# AADIdentityAPIConnector + +## Description + +Azure AD Identity API Connector diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/settings.json b/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/settings.json new file mode 100644 index 0000000000..327fd87153 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/settings.json @@ -0,0 +1,25 @@ +{ + "resourceName": "AADIdentityAPIConnector", + "description": "This resource configures an Azure AD Identity A P I Connector.", + "permissions": { + "graph": { + "delegated": { + "read": [ + + ], + "update": [ + + ] + }, + "application": { + "read": [ + + ], + "update": [ + + ] + } + } +} + +} diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADIdentityAPIConnector.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADIdentityAPIConnector.Tests.ps1 new file mode 100644 index 0000000000..18e4a5281a --- /dev/null +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADIdentityAPIConnector.Tests.ps1 @@ -0,0 +1,317 @@ +[CmdletBinding()] +param( +) +$M365DSCTestFolder = Join-Path -Path $PSScriptRoot ` + -ChildPath '..\..\Unit' ` + -Resolve +$CmdletModule = (Join-Path -Path $M365DSCTestFolder ` + -ChildPath '\Stubs\Microsoft365.psm1' ` + -Resolve) +$GenericStubPath = (Join-Path -Path $M365DSCTestFolder ` + -ChildPath '\Stubs\Generic.psm1' ` + -Resolve) +Import-Module -Name (Join-Path -Path $M365DSCTestFolder ` + -ChildPath '\UnitTestHelper.psm1' ` + -Resolve) + +$Global:DscHelper = New-M365DscUnitTestHelper -StubModule $CmdletModule ` + -DscResource "AADIdentityAPIConnector" -GenericStubModule $GenericStubPath +Describe -Name $Global:DscHelper.DescribeHeader -Fixture { + InModuleScope -ModuleName $Global:DscHelper.ModuleName -ScriptBlock { + Invoke-Command -ScriptBlock $Global:DscHelper.InitializeScript -NoNewScope + BeforeAll { + + $secpasswd = ConvertTo-SecureString (New-Guid | Out-String) -AsPlainText -Force + $Credential = New-Object System.Management.Automation.PSCredential ('tenantadmin@mydomain.com', $secpasswd) + + Mock -CommandName Confirm-M365DSCDependencies -MockWith { + } + + Mock -CommandName Get-PSSession -MockWith { + } + + Mock -CommandName Remove-PSSession -MockWith { + } + + Mock -CommandName Update-MgBetaIdentityAPIConnector -MockWith { + } + + Mock -CommandName New-MgBetaIdentityAPIConnector -MockWith { + } + + Mock -CommandName Remove-MgBetaIdentityAPIConnector -MockWith { + } + + Mock -CommandName New-M365DSCConnection -MockWith { + return "Credentials" + } + + # Mock Write-Host to hide output during the tests + Mock -CommandName Write-Host -MockWith { + } + $Script:exportedInstances =$null + $Script:ExportMode = $false + } + # Test contexts + Context -Name "The AADIdentityAPIConnector should exist but it DOES NOT" -Fixture { + BeforeAll { + $testParams = @{ + AuthenticationConfiguration = (New-CimInstance -ClassName MSFT_MicrosoftGraphapiAuthenticationConfigurationBase -Property @{ + Password = "FakeStringValue" + Pkcs12Value = "FakeStringValue" + CertificateList = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_MicrosoftGraphpkcs12CertificateInformation -Property @{ + IsActive = $True + NotAfter = $True + Thumbprint = "FakeStringValue" + NotBefore = $True + } -ClientOnly) + ) + Username = "FakeStringValue" + odataType = "#microsoft.graph.basicAuthentication" + } -ClientOnly) + DisplayName = "FakeStringValue" + Id = "FakeStringValue" + TargetUrl = "FakeStringValue" + Ensure = "Present" + Credential = $Credential; + } + + Mock -CommandName Get-MgBetaIdentityAPIConnector -MockWith { + return $null + } + } + It 'Should return Values from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Absent' + } + It 'Should return false from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + It 'Should Create the group from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName New-MgBetaIdentityAPIConnector -Exactly 1 + } + } + + Context -Name "The AADIdentityAPIConnector exists but it SHOULD NOT" -Fixture { + BeforeAll { + $testParams = @{ + AuthenticationConfiguration = (New-CimInstance -ClassName MSFT_MicrosoftGraphapiAuthenticationConfigurationBase -Property @{ + Password = "FakeStringValue" + Pkcs12Value = "FakeStringValue" + CertificateList = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_MicrosoftGraphpkcs12CertificateInformation -Property @{ + IsActive = $True + NotAfter = $True + Thumbprint = "FakeStringValue" + NotBefore = $True + } -ClientOnly) + ) + Username = "FakeStringValue" + odataType = "#microsoft.graph.basicAuthentication" + } -ClientOnly) + DisplayName = "FakeStringValue" + Id = "FakeStringValue" + TargetUrl = "FakeStringValue" + Ensure = 'Absent' + Credential = $Credential; + } + + Mock -CommandName Get-MgBetaIdentityAPIConnector -MockWith { + return @{ + AdditionalProperties = @{ + '@odata.type' = "#microsoft.graph.IdentityApiConnector" + } + AuthenticationConfiguration = @{ + '@odata.type' = "#microsoft.graph.basicAuthentication" + Pkcs12Value = "FakeStringValue" + Password = "FakeStringValue" + Username = "FakeStringValue" + CertificateList = @( + @{ + IsActive = $True + NotAfter = $True + Thumbprint = "FakeStringValue" + NotBefore = $True + } + ) + } + DisplayName = "FakeStringValue" + Id = "FakeStringValue" + TargetUrl = "FakeStringValue" + + } + } + } + + It 'Should return Values from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + + It 'Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should Remove the group from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName Remove-MgBetaIdentityAPIConnector -Exactly 1 + } + } + Context -Name "The AADIdentityAPIConnector Exists and Values are already in the desired state" -Fixture { + BeforeAll { + $testParams = @{ + AuthenticationConfiguration = (New-CimInstance -ClassName MSFT_MicrosoftGraphapiAuthenticationConfigurationBase -Property @{ + Password = "FakeStringValue" + Pkcs12Value = "FakeStringValue" + CertificateList = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_MicrosoftGraphpkcs12CertificateInformation -Property @{ + IsActive = $True + NotAfter = $True + Thumbprint = "FakeStringValue" + NotBefore = $True + } -ClientOnly) + ) + Username = "FakeStringValue" + odataType = "#microsoft.graph.basicAuthentication" + } -ClientOnly) + DisplayName = "FakeStringValue" + Id = "FakeStringValue" + TargetUrl = "FakeStringValue" + Ensure = 'Present' + Credential = $Credential; + } + + Mock -CommandName Get-MgBetaIdentityAPIConnector -MockWith { + return @{ + AdditionalProperties = @{ + '@odata.type' = "#microsoft.graph.IdentityApiConnector" + } + AuthenticationConfiguration = @{ + '@odata.type' = "#microsoft.graph.basicAuthentication" + Pkcs12Value = "FakeStringValue" + Password = "FakeStringValue" + Username = "FakeStringValue" + CertificateList = @( + @{ + IsActive = $True + NotAfter = $True + Thumbprint = "FakeStringValue" + NotBefore = $True + } + ) + } + DisplayName = "FakeStringValue" + Id = "FakeStringValue" + TargetUrl = "FakeStringValue" + + } + } + } + + + It 'Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $true + } + } + + Context -Name "The AADIdentityAPIConnector exists and values are NOT in the desired state" -Fixture { + BeforeAll { + $testParams = @{ + AuthenticationConfiguration = (New-CimInstance -ClassName MSFT_MicrosoftGraphapiAuthenticationConfigurationBase -Property @{ + Password = "FakeStringValue" + Pkcs12Value = "FakeStringValue" + CertificateList = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_MicrosoftGraphpkcs12CertificateInformation -Property @{ + IsActive = $True + NotAfter = $True + Thumbprint = "FakeStringValue" + NotBefore = $True + } -ClientOnly) + ) + Username = "FakeStringValue" + odataType = "#microsoft.graph.basicAuthentication" + } -ClientOnly) + DisplayName = "FakeStringValue" + Id = "FakeStringValue" + TargetUrl = "FakeStringValue" + Ensure = 'Present' + Credential = $Credential; + } + + Mock -CommandName Get-MgBetaIdentityAPIConnector -MockWith { + return @{ + AuthenticationConfiguration = @{ + '@odata.type' = "#microsoft.graph.basicAuthentication" + Pkcs12Value = "FakeStringValue" + Password = "FakeStringValue" + Username = "FakeStringValue" + CertificateList = @( + @{ + Thumbprint = "FakeStringValue" + } + ) + } + DisplayName = "FakeStringValue" + Id = "FakeStringValue" + TargetUrl = "FakeStringValue" + } + } + } + + It 'Should return Values from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + + It 'Should return false from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should call the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName Update-MgBetaIdentityAPIConnector -Exactly 1 + } + } + + Context -Name 'ReverseDSC Tests' -Fixture { + BeforeAll { + $Global:CurrentModeIsExport = $true + $Global:PartialExportFileName = "$(New-Guid).partial.ps1" + $testParams = @{ + Credential = $Credential + } + + Mock -CommandName Get-MgBetaIdentityAPIConnector -MockWith { + return @{ + AdditionalProperties = @{ + '@odata.type' = "#microsoft.graph.IdentityApiConnector" + } + AuthenticationConfiguration = @{ + '@odata.type' = "#microsoft.graph.basicAuthentication" + Pkcs12Value = "FakeStringValue" + Password = "FakeStringValue" + Username = "FakeStringValue" + CertificateList = @( + @{ + IsActive = $True + NotAfter = $True + Thumbprint = "FakeStringValue" + NotBefore = $True + } + ) + } + DisplayName = "FakeStringValue" + Id = "FakeStringValue" + TargetUrl = "FakeStringValue" + + } + } + } + It 'Should Reverse Engineer resource from the Export method' { + $result = Export-TargetResource @testParams + $result | Should -Not -BeNullOrEmpty + } + } + } +} + +Invoke-Command -ScriptBlock $Global:DscHelper.CleanupScript -NoNewScope diff --git a/Tests/Unit/Stubs/Microsoft365.psm1 b/Tests/Unit/Stubs/Microsoft365.psm1 index cdcf592740..f44a1bebb7 100644 --- a/Tests/Unit/Stubs/Microsoft365.psm1 +++ b/Tests/Unit/Stubs/Microsoft365.psm1 @@ -97638,3 +97638,290 @@ function Invoke-PnPSPRestMethod $Content ) } +#region MgBetaIdentityAPIConnector +function Get-MgBetaIdentityApiConnector +{ + [CmdletBinding()] + param + ( + [Parameter()] + [System.String] + $IdentityApiConnectorId, + + [Parameter()] + [PSObject] + $InputObject, + + [Parameter()] + [System.String[]] + $ExpandProperty, + + [Parameter()] + [System.String[]] + $Property, + + [Parameter()] + [System.String] + $Filter, + + [Parameter()] + [System.String] + $Search, + + [Parameter()] + [System.Int32] + $Skip, + + [Parameter()] + [System.String[]] + $Sort, + + [Parameter()] + [System.Int32] + $Top, + + [Parameter()] + [System.String] + $ResponseHeadersVariable, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Break, + + [Parameter()] + [System.Collections.IDictionary] + $Headers, + + [Parameter()] + [PSObject[]] + $HttpPipelineAppend, + + [Parameter()] + [PSObject[]] + $HttpPipelinePrepend, + + [Parameter()] + [System.Uri] + $Proxy, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ProxyCredential, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $ProxyUseDefaultCredentials, + + [Parameter()] + [System.Int32] + $PageSize, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $All, + + [Parameter()] + [System.String] + $CountVariable + ) +} + +function New-MgBetaIdentityApiConnector +{ + [CmdletBinding()] + param + ( + [Parameter()] + [PSObject] + $BodyParameter, + + [Parameter()] + [System.String] + $ResponseHeadersVariable, + + [Parameter()] + [System.Collections.Hashtable] + $AdditionalProperties, + + [Parameter()] + [System.Collections.Hashtable] + $AuthenticationConfiguration, + + [Parameter()] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [System.String] + $TargetUrl, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Break, + + [Parameter()] + [System.Collections.IDictionary] + $Headers, + + [Parameter()] + [PSObject[]] + $HttpPipelineAppend, + + [Parameter()] + [PSObject[]] + $HttpPipelinePrepend, + + [Parameter()] + [System.Uri] + $Proxy, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ProxyCredential, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $ProxyUseDefaultCredentials, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Confirm + ) +} + +function Remove-MgBetaIdentityApiConnector +{ + [CmdletBinding()] + param + ( + [Parameter()] + [System.String] + $IdentityApiConnectorId, + + [Parameter()] + [PSObject] + $InputObject, + + [Parameter()] + [System.String] + $ResponseHeadersVariable, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Break, + + [Parameter()] + [System.Collections.IDictionary] + $Headers, + + [Parameter()] + [PSObject[]] + $HttpPipelineAppend, + + [Parameter()] + [PSObject[]] + $HttpPipelinePrepend, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $PassThru, + + [Parameter()] + [System.Uri] + $Proxy, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ProxyCredential, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $ProxyUseDefaultCredentials, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Confirm + ) +} + +function Update-MgBetaIdentityApiConnector +{ + [CmdletBinding()] + param + ( + [Parameter()] + [System.String] + $IdentityApiConnectorId, + + [Parameter()] + [PSObject] + $InputObject, + + [Parameter()] + [PSObject] + $BodyParameter, + + [Parameter()] + [System.String] + $ResponseHeadersVariable, + + [Parameter()] + [System.Collections.Hashtable] + $AdditionalProperties, + + [Parameter()] + [System.Collections.Hashtable] + $AuthenticationConfiguration, + + [Parameter()] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [System.String] + $TargetUrl, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Break, + + [Parameter()] + [System.Collections.IDictionary] + $Headers, + + [Parameter()] + [PSObject[]] + $HttpPipelineAppend, + + [Parameter()] + [PSObject[]] + $HttpPipelinePrepend, + + [Parameter()] + [System.Uri] + $Proxy, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ProxyCredential, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $ProxyUseDefaultCredentials, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Confirm + ) +} + +#endregion + From 113ce98c372fae7c5c9adebe3c2812d129433e30 Mon Sep 17 00:00:00 2001 From: "Kartikeya Saxena (from Dev Box)" Date: Tue, 22 Oct 2024 10:29:17 +0530 Subject: [PATCH 02/11] Making changes for certificates --- .../MSFT_AADIdentityAPIConnector.psm1 | 54 ++++++++++++++----- .../MSFT_AADIdentityAPIConnector.schema.mof | 11 +++- 2 files changed, 51 insertions(+), 14 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.psm1 index 1c6c4bc75d..60f6d95ac3 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.psm1 @@ -26,8 +26,8 @@ function Get-TargetResource $Password, [Parameter()] - [System.Management.Automation.PSCredential] - $Pkcs12Value, + [Microsoft.Management.Infrastructure.CimInstance[]] + $Certificates, #endregion @@ -121,10 +121,19 @@ function Get-TargetResource $Password = New-Object System.Management.Automation.PSCredential ('Password', $securePassword) } - if($null -ne $getValue.AuthenticationConfiguration.AdditionalProperties.pkcs12Value) { - $securePassword = ConvertTo-SecureString $getValue.AuthenticationConfiguration.AdditionalProperties.pkcs12Value -AsPlainText -Force - $pkcs12Value = New-Object System.Management.Automation.PSCredential ('pkcs12Value', $securePassword) + $complexCertificates = @() + foreach ($currentCertificate in $getValue.AuthenticationConfiguration.AdditionalProperties.certificateList) + { + $myCertificate= @{} + $myCertificate.Add('Pkcs12Value', "Please insert a valid Pkcs12Value") + $myCertificate.Add('Thumbprint', $currentCertificate.thumbprint) + $myCertificate.Add('IsActive', $currentCertificate.isActive) + + if ($myCertificate.values.Where({$null -ne $_}).Count -gt 0) + { + $complexCertificates += $myCertificate + } } #endregion @@ -135,7 +144,7 @@ function Get-TargetResource Id = $getValue.Id Username = $getValue.AuthenticationConfiguration.AdditionalProperties.username Password = $Password - Pkcs12Value = $pkcs12Value + Certificates = $complexCertificates Ensure = 'Present' Credential = $Credential ApplicationId = $ApplicationId @@ -187,8 +196,8 @@ function Set-TargetResource $Password, [Parameter()] - [System.Management.Automation.PSCredential] - $Pkcs12Value, + [Microsoft.Management.Infrastructure.CimInstance[]] + $Certificates, #endregion @@ -321,8 +330,8 @@ function Test-TargetResource $Password, [Parameter()] - [System.Management.Automation.PSCredential] - $Pkcs12Value, + [Microsoft.Management.Infrastructure.CimInstance[]] + $Certificates, #endregion @@ -526,11 +535,25 @@ function Export-TargetResource $Results = Get-TargetResource @Params $Results.Password = "New-Object System.Management.Automation.PSCredential('Password', (ConvertTo-SecureString ((New-Guid).ToString()) -AsPlainText -Force));" - $Results.Pkcs12Value = "New-Object System.Management.Automation.PSCredential('Pkcs12Value', (ConvertTo-SecureString ((New-Guid).ToString()) -AsPlainText -Force));" - $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` -Results $Results + + if ($null -ne $Results.Certificates) + { + $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString ` + -ComplexObject $Results.Certificates` + -CIMInstanceName 'AADIdentityAPIConnectionCertificate' + if (-not [String]::IsNullOrWhiteSpace($complexTypeStringResult)) + { + $Results.Certificates = $complexTypeStringResult + } + else + { + $Results.Remove('Certificates') | Out-Null + } + } + $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName ` -ConnectionMode $ConnectionMode ` -ModulePath $PSScriptRoot ` @@ -538,9 +561,14 @@ function Export-TargetResource -Credential $Credential - $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName 'Pkcs12Value' $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName 'Password' + + if ($Results.Certificates) + { + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName "Certificates" -IsCIMArray:$True + } + $dscContent += $currentDSCBlock Save-M365DSCPartialExport -Content $currentDSCBlock ` -FileName $Global:PartialExportFileName diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.schema.mof index 7c359ad403..8407b6ae24 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.schema.mof +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.schema.mof @@ -1,3 +1,12 @@ +[ClassVersion("1.0.0")] +class MSFT_AADIdentityAPIConnectionCertificate +{ + [Write, Description("")] String Pkcs12Value; + [Write, Description("")] String Thumbprint; + [Write, Description("")] Boolean IsActive; +}; + + [ClassVersion("1.0.0.0"), FriendlyName("AADIdentityAPIConnector")] class MSFT_AADIdentityAPIConnector : OMI_BaseResource { @@ -6,7 +15,7 @@ class MSFT_AADIdentityAPIConnector : OMI_BaseResource [Key, Description("The unique identifier for an entity. Read-only.")] String Id; [Write, Description("The username of the password")] String Username; [Write, Description("The password of certificate/basic auth"), EmbeddedInstance("MSFT_Credential")] String Password; - [Write, Description("The Pkcs12Value of the certificate"), EmbeddedInstance("MSFT_Credential")] String Pkcs12Value; + [Write, Description(""), EmbeddedInstance("MSFT_AADIdentityAPIConnectionCertificate")] String Certificates[]; [Write, Description("Present ensures the policy exists, absent ensures it is removed."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] string Ensure; [Write, Description("Credentials of the Admin"), EmbeddedInstance("MSFT_Credential")] string Credential; [Write, Description("Id of the Azure Active Directory application to authenticate with.")] String ApplicationId; From c213db26a2c6663bb3d79c382e6651bbcb9f6f21 Mon Sep 17 00:00:00 2001 From: "Kartikeya Saxena (from Dev Box)" Date: Tue, 22 Oct 2024 10:54:30 +0530 Subject: [PATCH 03/11] temp --- .../MSFT_AADIdentityAPIConnector.psm1 | 83 +++++++++++-------- 1 file changed, 48 insertions(+), 35 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.psm1 index 60f6d95ac3..bf311e9b62 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.psm1 @@ -251,54 +251,67 @@ function Set-TargetResource $BoundParameters = Remove-M365DSCAuthenticationParameter -BoundParameters $PSBoundParameters + # If the certificates array is not empty, then we need to create a new instance of New-MgBetaAADIdentityAPIConnector - if ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Absent') - { - Write-Verbose -Message "Creating an Azure AD Identity API Connector with DisplayName {$DisplayName}" + $needToUpdateCertificates = $false + if($null -ne $Certificates -and $Certificates.Count -gt 0) { + $needToUpdateCertificates = $true + } - $createParameters = ([Hashtable]$BoundParameters).Clone() - $createParameters = Rename-M365DSCCimInstanceParameter -Properties $createParameters - $createParameters.Remove('Id') | Out-Null + if($needToUpdateCertificates -eq $false) { + if ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Absent') + { + Write-Verbose -Message "Creating an Azure AD Identity API Connector with DisplayName {$DisplayName}" - $createParameters.Remove('Password') | Out-Null - $createParameters.Remove('Pkcs12Value') | Out-Null + $createParameters = ([Hashtable]$BoundParameters).Clone() + $createParameters = Rename-M365DSCCimInstanceParameter -Properties $createParameters + $createParameters.Remove('Id') | Out-Null - $createParameters.Add("AuthenticationConfiguration", @{ - '@odata.type' = "microsoft.graph.basicAuthentication" - "password" = $Password.GetNetworkCredential().Password - "username" = $Username - }) + $createParameters.Remove('Password') | Out-Null + $createParameters.Remove('Pkcs12Value') | Out-Null - $createParameters.Add("@odata.type", "#microsoft.graph.IdentityApiConnector") - $policy = New-MgBetaIdentityAPIConnector -BodyParameter $createParameters - } - elseif ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Present') - { - Write-Verbose -Message "Updating the Azure AD Identity API Connector with Id {$($currentInstance.Id)}" + if($username -ne $null) { + $createParameters.Add("AuthenticationConfiguration", @{ + '@odata.type' = "microsoft.graph.basicAuthentication" + "password" = $Password.GetNetworkCredential().Password + "username" = $Username + }) + } - $updateParameters = ([Hashtable]$BoundParameters).Clone() - $updateParameters = Rename-M365DSCCimInstanceParameter -Properties $updateParameters + $createParameters.Add("@odata.type", "#microsoft.graph.IdentityApiConnector") + $policy = New-MgBetaIdentityAPIConnector -BodyParameter $createParameters + } + elseif ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Present') + { + Write-Verbose -Message "Updating the Azure AD Identity API Connector with Id {$($currentInstance.Id)}" + + $updateParameters = ([Hashtable]$BoundParameters).Clone() + $updateParameters = Rename-M365DSCCimInstanceParameter -Properties $updateParameters - $updateParameters.Remove('Id') | Out-Null + $updateParameters.Remove('Id') | Out-Null - $updateParameters.Remove('Password') | Out-Null - $updateParameters.Remove('Pkcs12Value') | Out-Null + $updateParameters.Remove('Password') | Out-Null + $updateParameters.Remove('Pkcs12Value') | Out-Null - $updateParameters.Add("AuthenticationConfiguration", @{ - '@odata.type' = "microsoft.graph.basicAuthentication" - "password" = $Password.GetNetworkCredential().Password - "username" = $Username - }) + $updateParameters.Add("AuthenticationConfiguration", @{ + '@odata.type' = "microsoft.graph.basicAuthentication" + "password" = $Password.GetNetworkCredential().Password + "username" = $Username + }) - $UpdateParameters.Add("@odata.type", "#microsoft.graph.IdentityApiConnector") - Update-MgBetaIdentityAPIConnector ` + $UpdateParameters.Add("@odata.type", "#microsoft.graph.IdentityApiConnector") + Update-MgBetaIdentityAPIConnector ` -IdentityApiConnectorId $currentInstance.Id ` -BodyParameter $UpdateParameters + } + elseif ($Ensure -eq 'Absent' -and $currentInstance.Ensure -eq 'Present') + { + Write-Verbose -Message "Removing the Azure AD Identity API Connector with Id {$($currentInstance.Id)}" + Remove-MgBetaIdentityAPIConnector -IdentityApiConnectorId $currentInstance.Id + } } - elseif ($Ensure -eq 'Absent' -and $currentInstance.Ensure -eq 'Present') - { - Write-Verbose -Message "Removing the Azure AD Identity API Connector with Id {$($currentInstance.Id)}" - Remove-MgBetaIdentityAPIConnector -IdentityApiConnectorId $currentInstance.Id + else { + Remove-MgBetaIdentityAPIConnector -IdentityApiConnectorId $currentInstance.Id } } From d4aa20d86537a434b2e4babf5dbb8de29331db7c Mon Sep 17 00:00:00 2001 From: "Kartikeya Saxena (from Dev Box)" Date: Tue, 22 Oct 2024 15:19:07 +0530 Subject: [PATCH 04/11] added logic to upload certificates --- .../MSFT_AADIdentityAPIConnector.psm1 | 85 ++++++++++++++++++- .../MSFT_AADIdentityAPIConnector.schema.mof | 1 + 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.psm1 index bf311e9b62..8218e0f355 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.psm1 @@ -128,6 +128,7 @@ function Get-TargetResource $myCertificate= @{} $myCertificate.Add('Pkcs12Value', "Please insert a valid Pkcs12Value") $myCertificate.Add('Thumbprint', $currentCertificate.thumbprint) + $myCertificate.Add('Password', "Please insert a valid Password for the certificate") $myCertificate.Add('IsActive', $currentCertificate.isActive) if ($myCertificate.values.Where({$null -ne $_}).Count -gt 0) @@ -311,7 +312,90 @@ function Set-TargetResource } } else { + + # Remove the existing instance if already present + if($currentInstance.Ensure -ne 'Absent') { + Write-Verbose -Message "Removing the Azure AD Identity API Connector with Id {$($currentInstance.Id)}" Remove-MgBetaIdentityAPIConnector -IdentityApiConnectorId $currentInstance.Id + } + + # Create a new instance with the certificates + Write-Verbose -Message "Creating an Azure AD Identity API Connector with DisplayName {$DisplayName}" + + $createParameters = ([Hashtable]$BoundParameters).Clone() + $createParameters = Rename-M365DSCCimInstanceParameter -Properties $createParameters + $createParameters.Remove('Id') | Out-Null + + $createParameters.Remove('Password') | Out-Null + $createParameters.Remove('Pkcs12Value') | Out-Null + + # Get the active and inactive certificates + $activeCertificates = @() + $inactiveCertificates = @() + foreach ($currentCertificate in $Certificates) + { + $myCertificate = @{} + $myCertificate.Add('Pkcs12Value', $currentCertificate.Pkcs12Value) + $myCertificate.Add('Password', $currentCertificate.Password) + + if($currentCertificate.IsActive -eq $true) { + $activeCertificates += $myCertificate + } + else { + $inactiveCertificates += $myCertificate + } + } + + # Only one certificate can be active + if($activeCertificates.Count -ne 1) { + Write-Error "There should be one active certificate" + throw + } + + if($inactiveCertificates.Count -eq 0) { + $createParameters.Add("AuthenticationConfiguration", @{ + '@odata.type' = "microsoft.graph.pkcs12Certificate" + "password" = $activeCertificates[0].Password + "pkcs12Value" = $activeCertificates[0].Pkcs12Value + }) + $activeCertificates = $activeCertificates[1..$activeCertificates.Count] + } + else { + $createParameters.Add("AuthenticationConfiguration", @{ + '@odata.type' = "microsoft.graph.pkcs12Certificate" + "password" = $inactiveCertificates[0].Password + "pkcs12Value" = $inactiveCertificates[0].Pkcs12Value + }) + # remove the first element from the inactive certificates + $inactiveCertificates = $inactiveCertificates[1..$inactiveCertificates.Count] + } + + $createParameters.Add("@odata.type", "#microsoft.graph.IdentityApiConnector") + $policy = New-MgBetaIdentityAPIConnector -BodyParameter $createParameters + + + # Upload the inactive certificates + foreach ($currentCertificate in $inactiveCertificates) + { + $params = @{ + pkcs12Value = $currentCertificate.Pkcs12Value + password = $currentCertificate.Password + } + + Invoke-MgBetaUploadIdentityApiConnectorClientCertificate -IdentityApiConnectorId $policy.Id -BodyParameter $params + } + + # Upload active certificate + foreach ($currentCertificate in $activeCertificates) + { + $params = @{ + pkcs12Value = $currentCertificate.Pkcs12Value + password = $currentCertificate.Password + } + + Invoke-MgBetaUploadIdentityApiConnectorClientCertificate -IdentityApiConnectorId $policy.Id -BodyParameter $params + } + } } @@ -428,7 +512,6 @@ function Test-TargetResource $ValuesToCheck.Remove('Id') | Out-Null $ValuesToCheck.Remove('Password') | Out-Null - $ValuesToCheck.Remove('Pkcs12Value') | Out-Null $ValuesToCheck = Remove-M365DSCAuthenticationParameter -BoundParameters $ValuesToCheck Write-Verbose -Message "Current Values: $(Convert-M365DscHashtableToString -Hashtable $CurrentValues)" diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.schema.mof index 8407b6ae24..32f16ddc5e 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.schema.mof +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.schema.mof @@ -3,6 +3,7 @@ class MSFT_AADIdentityAPIConnectionCertificate { [Write, Description("")] String Pkcs12Value; [Write, Description("")] String Thumbprint; + [Write, Description("")] String Password; [Write, Description("")] Boolean IsActive; }; From d239edb117fa83ef32ff0779888321e2b31bc7c0 Mon Sep 17 00:00:00 2001 From: "Kartikeya Saxena (from Dev Box)" Date: Tue, 22 Oct 2024 17:22:16 +0530 Subject: [PATCH 05/11] Added MSFT_Credentials in password and pkcs12Value --- .../MSFT_AADIdentityAPIConnector.psm1 | 14 ++++---------- .../MSFT_AADIdentityAPIConnector.schema.mof | 4 ++-- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.psm1 index 8218e0f355..60116d209c 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.psm1 @@ -97,10 +97,7 @@ function Get-TargetResource { $getValue = Get-MgBetaIdentityAPIConnector ` -Filter "DisplayName eq '$DisplayName'" ` - -ErrorAction SilentlyContinue | Where-Object ` - -FilterScript { - $_.AdditionalProperties.'@odata.type' -eq "#microsoft.graph.IdentityApiConnector" - } + -ErrorAction SilentlyContinue } } #endregion @@ -335,8 +332,8 @@ function Set-TargetResource foreach ($currentCertificate in $Certificates) { $myCertificate = @{} - $myCertificate.Add('Pkcs12Value', $currentCertificate.Pkcs12Value) - $myCertificate.Add('Password', $currentCertificate.Password) + $myCertificate.Add('Pkcs12Value', ($currentCertificate.Pkcs12Value).Password) + $myCertificate.Add('Password', ($currentCertificate.Password).Password) if($currentCertificate.IsActive -eq $true) { $activeCertificates += $myCertificate @@ -629,7 +626,7 @@ function Export-TargetResource } $Results = Get-TargetResource @Params - $Results.Password = "New-Object System.Management.Automation.PSCredential('Password', (ConvertTo-SecureString ((New-Guid).ToString()) -AsPlainText -Force));" + $Results.Password = "Please insert a valid Password" $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` -Results $Results @@ -657,9 +654,6 @@ function Export-TargetResource -Credential $Credential - $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName 'Password' - - if ($Results.Certificates) { $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName "Certificates" -IsCIMArray:$True diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.schema.mof index 32f16ddc5e..9d7db64611 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.schema.mof +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.schema.mof @@ -1,9 +1,9 @@ [ClassVersion("1.0.0")] class MSFT_AADIdentityAPIConnectionCertificate { - [Write, Description("")] String Pkcs12Value; + [Write, Description(""), EmbeddedInstance("MSFT_Credential")] String Pkcs12Value; [Write, Description("")] String Thumbprint; - [Write, Description("")] String Password; + [Write, Description(""), EmbeddedInstance("MSFT_Credential")] String Password; [Write, Description("")] Boolean IsActive; }; From 48efcff2752562b398cccffe1416670c90972b77 Mon Sep 17 00:00:00 2001 From: "Kartikeya Saxena (from Dev Box)" Date: Tue, 22 Oct 2024 20:00:54 +0530 Subject: [PATCH 06/11] Fixed Test Target Resource --- .../MSFT_AADIdentityAPIConnector.psm1 | 60 +++++++++++++++++-- 1 file changed, 54 insertions(+), 6 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.psm1 index 60116d209c..04f48ad77f 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.psm1 @@ -494,16 +494,64 @@ function Test-TargetResource $target = $CurrentValues.$key if ($null -ne $source -and $source.GetType().Name -like '*CimInstance*') { - $testResult = Compare-M365DSCComplexObject ` - -Source ($source) ` - -Target ($target) + + # create a list of thumbprints from the source list + $sourceThumbprints = @() + foreach ($item in $source) + { + $myCertificate = @{} + $myCertificate.Add('Thumbprint', $item.Thumbprint) + $myCertificate.Add('IsActive', $item.IsActive) + $sourceThumbprints += $myCertificate + } + + # create a list of thumbprints from the target list + $targetThumbprints = @() + foreach ($item in $target) + { + $myCertificate = @{} + $myCertificate.Add('Thumbprint', $item.Thumbprint) + $myCertificate.Add('IsActive', $item.IsActive) + $targetThumbprints += $myCertificate + } + # sort the lists + $sourceThumbprints = $sourceThumbprints | Sort-Object -Property { $_.Thumbprint } + $targetThumbprints = $targetThumbprints | Sort-Object -Property { $_.Thumbprint } + + # print the list in verbose logs + foreach ($item in $sourceThumbprints) + { + Write-Verbose -Message "Source Thumbprints: $(Convert-M365DscHashtableToString -Hashtable $item)" + } - if (-not $testResult) + foreach ($item in $targetThumbprints) { - break + Write-Verbose -Message "Target Thumbprints: $(Convert-M365DscHashtableToString -Hashtable $item)" + } + + # check if the lists are identical + $compareResult = $true + if ($sourceThumbprints.Count -ne $targetThumbprints.Count) + { + $compareResult = $false + } + else + { + for ($i = 0; $i -lt $sourceThumbprints.Count; $i++) + { + if ($sourceThumbprints[$i].Thumbprint -ne $targetThumbprints[$i].Thumbprint) + { + $compareResult = $false + Write-Verbose -Message "Thumbprint mismatch: $($sourceThumbprints[$i].Thumbprint) - $($targetThumbprints[$i].Thumbprint)" + break + } + } } - $ValuesToCheck.Remove($key) | Out-Null + if($compareResult -eq $true) + { + $ValuesToCheck.Remove($key) | Out-Null + } } } From ab76a26424d7b77598b701d06d167a80e00123b8 Mon Sep 17 00:00:00 2001 From: "Kartikeya Saxena (from Dev Box)" Date: Wed, 23 Oct 2024 11:55:16 +0530 Subject: [PATCH 07/11] Added UTs --- .../MSFT_AADIdentityAPIConnector.schema.mof | 10 +- ...ft365DSC.AADIdentityAPIConnector.Tests.ps1 | 225 +++++++----------- 2 files changed, 88 insertions(+), 147 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.schema.mof index 9d7db64611..447b39d00d 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.schema.mof +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADIdentityAPIConnector/MSFT_AADIdentityAPIConnector.schema.mof @@ -1,10 +1,10 @@ [ClassVersion("1.0.0")] class MSFT_AADIdentityAPIConnectionCertificate { - [Write, Description(""), EmbeddedInstance("MSFT_Credential")] String Pkcs12Value; - [Write, Description("")] String Thumbprint; - [Write, Description(""), EmbeddedInstance("MSFT_Credential")] String Password; - [Write, Description("")] Boolean IsActive; + [Write, Description("Pkcs12Value of the certificate as a secure string in Base64 encoding"), EmbeddedInstance("MSFT_Credential")] String Pkcs12Value; + [Write, Description("Thumbprint of the certificate in Base64 encoding")] String Thumbprint; + [Write, Description("Password of the certificate as a secure string"), EmbeddedInstance("MSFT_Credential")] String Password; + [Write, Description("Tells if the certificate is in use or not")] Boolean IsActive; }; @@ -16,7 +16,7 @@ class MSFT_AADIdentityAPIConnector : OMI_BaseResource [Key, Description("The unique identifier for an entity. Read-only.")] String Id; [Write, Description("The username of the password")] String Username; [Write, Description("The password of certificate/basic auth"), EmbeddedInstance("MSFT_Credential")] String Password; - [Write, Description(""), EmbeddedInstance("MSFT_AADIdentityAPIConnectionCertificate")] String Certificates[]; + [Write, Description("List of certificates to be used in the API connector"), EmbeddedInstance("MSFT_AADIdentityAPIConnectionCertificate")] String Certificates[]; [Write, Description("Present ensures the policy exists, absent ensures it is removed."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] string Ensure; [Write, Description("Credentials of the Admin"), EmbeddedInstance("MSFT_Credential")] string Credential; [Write, Description("Id of the Azure Active Directory application to authenticate with.")] String ApplicationId; diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADIdentityAPIConnector.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADIdentityAPIConnector.Tests.ps1 index 18e4a5281a..8fcde7f64b 100644 --- a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADIdentityAPIConnector.Tests.ps1 +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADIdentityAPIConnector.Tests.ps1 @@ -55,26 +55,28 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { # Test contexts Context -Name "The AADIdentityAPIConnector should exist but it DOES NOT" -Fixture { BeforeAll { + $testParams = @{ - AuthenticationConfiguration = (New-CimInstance -ClassName MSFT_MicrosoftGraphapiAuthenticationConfigurationBase -Property @{ - Password = "FakeStringValue" - Pkcs12Value = "FakeStringValue" - CertificateList = [CimInstance[]]@( - (New-CimInstance -ClassName MSFT_MicrosoftGraphpkcs12CertificateInformation -Property @{ - IsActive = $True - NotAfter = $True - Thumbprint = "FakeStringValue" - NotBefore = $True - } -ClientOnly) - ) - Username = "FakeStringValue" - odataType = "#microsoft.graph.basicAuthentication" - } -ClientOnly) - DisplayName = "FakeStringValue" - Id = "FakeStringValue" - TargetUrl = "FakeStringValue" - Ensure = "Present" - Credential = $Credential; + DisplayName = 'FakeStringValue' + TargetUrl = 'FakeStringValue' + Id = 'FakeStringValue' + Username = 'FakeStringValue' + Password = $Credential + Certificates = @( + New-CimInstance -ClassName 'MSFT_AADIdentityAPIConnectionCertificate' -Property @{ + Thumbprint = 'FakeStringValue' + Pkcs12Value = (New-CimInstance -ClassName 'MSFT_Credential' -Property @{ + Username = 'FakeStringValue' + Password = 'FakeStringValue' + } -ClientOnly) + Password = (New-CimInstance -ClassName 'MSFT_Credential' -Property @{ + Username = 'FakeStringValue' + Password = 'FakeStringValue' + } -ClientOnly) + IsActive = $true + } -ClientOnly + ) + Credential = $Credential } Mock -CommandName Get-MgBetaIdentityAPIConnector -MockWith { @@ -96,50 +98,40 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Context -Name "The AADIdentityAPIConnector exists but it SHOULD NOT" -Fixture { BeforeAll { $testParams = @{ - AuthenticationConfiguration = (New-CimInstance -ClassName MSFT_MicrosoftGraphapiAuthenticationConfigurationBase -Property @{ - Password = "FakeStringValue" - Pkcs12Value = "FakeStringValue" - CertificateList = [CimInstance[]]@( - (New-CimInstance -ClassName MSFT_MicrosoftGraphpkcs12CertificateInformation -Property @{ - IsActive = $True - NotAfter = $True - Thumbprint = "FakeStringValue" - NotBefore = $True - } -ClientOnly) - ) - Username = "FakeStringValue" - odataType = "#microsoft.graph.basicAuthentication" - } -ClientOnly) - DisplayName = "FakeStringValue" - Id = "FakeStringValue" - TargetUrl = "FakeStringValue" + DisplayName = 'FakeStringValue' + TargetUrl = 'FakeStringValue' + Id = 'FakeStringValue' + Username = 'FakeStringValue' + Password = $Credential + Certificates = @( + New-CimInstance -ClassName 'MSFT_AADIdentityAPIConnectionCertificate' -Property @{ + Thumbprint = 'FakeStringValue' + Pkcs12Value = (New-CimInstance -ClassName 'MSFT_Credential' -Property @{ + Username = 'FakeStringValue' + Password = 'FakeStringValue' + } -ClientOnly) + Password = (New-CimInstance -ClassName 'MSFT_Credential' -Property @{ + Username = 'FakeStringValue' + Password = 'FakeStringValue' + } -ClientOnly) + IsActive = $true + } -ClientOnly + ) + Credential = $Credential Ensure = 'Absent' - Credential = $Credential; } Mock -CommandName Get-MgBetaIdentityAPIConnector -MockWith { return @{ - AdditionalProperties = @{ - '@odata.type' = "#microsoft.graph.IdentityApiConnector" - } + DisplayName = 'FakeStringValue' + TargetUrl = 'FakeStringValue' + Id = 'FakeStringValue' AuthenticationConfiguration = @{ - '@odata.type' = "#microsoft.graph.basicAuthentication" - Pkcs12Value = "FakeStringValue" - Password = "FakeStringValue" - Username = "FakeStringValue" - CertificateList = @( - @{ - IsActive = $True - NotAfter = $True - Thumbprint = "FakeStringValue" - NotBefore = $True - } - ) + AdditionalProperties = @{ + Username = 'FakeStringValue' + Password = $Cred + } } - DisplayName = "FakeStringValue" - Id = "FakeStringValue" - TargetUrl = "FakeStringValue" - } } } @@ -159,51 +151,28 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { } Context -Name "The AADIdentityAPIConnector Exists and Values are already in the desired state" -Fixture { BeforeAll { + $testParams = @{ - AuthenticationConfiguration = (New-CimInstance -ClassName MSFT_MicrosoftGraphapiAuthenticationConfigurationBase -Property @{ - Password = "FakeStringValue" - Pkcs12Value = "FakeStringValue" - CertificateList = [CimInstance[]]@( - (New-CimInstance -ClassName MSFT_MicrosoftGraphpkcs12CertificateInformation -Property @{ - IsActive = $True - NotAfter = $True - Thumbprint = "FakeStringValue" - NotBefore = $True - } -ClientOnly) - ) - Username = "FakeStringValue" - odataType = "#microsoft.graph.basicAuthentication" - } -ClientOnly) - DisplayName = "FakeStringValue" - Id = "FakeStringValue" - TargetUrl = "FakeStringValue" + DisplayName = 'FakeStringValue' + TargetUrl = 'FakeStringValue' + Id = 'FakeStringValue' + Username = 'FakeStringValue' + Password = $Credential + Credential = $Credential Ensure = 'Present' - Credential = $Credential; } Mock -CommandName Get-MgBetaIdentityAPIConnector -MockWith { return @{ - AdditionalProperties = @{ - '@odata.type' = "#microsoft.graph.IdentityApiConnector" - } + DisplayName = 'FakeStringValue' + TargetUrl = 'FakeStringValue' + Id = 'FakeStringValue' AuthenticationConfiguration = @{ - '@odata.type' = "#microsoft.graph.basicAuthentication" - Pkcs12Value = "FakeStringValue" - Password = "FakeStringValue" - Username = "FakeStringValue" - CertificateList = @( - @{ - IsActive = $True - NotAfter = $True - Thumbprint = "FakeStringValue" - NotBefore = $True - } - ) + AdditionalProperties = @{ + Username = 'FakeStringValue' + Password = $Cred + } } - DisplayName = "FakeStringValue" - Id = "FakeStringValue" - TargetUrl = "FakeStringValue" - } } } @@ -215,45 +184,29 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { } Context -Name "The AADIdentityAPIConnector exists and values are NOT in the desired state" -Fixture { + BeforeAll { $testParams = @{ - AuthenticationConfiguration = (New-CimInstance -ClassName MSFT_MicrosoftGraphapiAuthenticationConfigurationBase -Property @{ - Password = "FakeStringValue" - Pkcs12Value = "FakeStringValue" - CertificateList = [CimInstance[]]@( - (New-CimInstance -ClassName MSFT_MicrosoftGraphpkcs12CertificateInformation -Property @{ - IsActive = $True - NotAfter = $True - Thumbprint = "FakeStringValue" - NotBefore = $True - } -ClientOnly) - ) - Username = "FakeStringValue" - odataType = "#microsoft.graph.basicAuthentication" - } -ClientOnly) - DisplayName = "FakeStringValue" - Id = "FakeStringValue" - TargetUrl = "FakeStringValue" + DisplayName = 'FakeStringValue2' #drift + TargetUrl = 'FakeStringValue' + Id = 'FakeStringValue' + Username = 'FakeStringValue' + Password = $Credential + Credential = $Credential Ensure = 'Present' - Credential = $Credential; } Mock -CommandName Get-MgBetaIdentityAPIConnector -MockWith { return @{ + DisplayName = 'FakeStringValue' + TargetUrl = 'FakeStringValue' + Id = 'FakeStringValue' AuthenticationConfiguration = @{ - '@odata.type' = "#microsoft.graph.basicAuthentication" - Pkcs12Value = "FakeStringValue" - Password = "FakeStringValue" - Username = "FakeStringValue" - CertificateList = @( - @{ - Thumbprint = "FakeStringValue" - } - ) + AdditionalProperties = @{ + Username = 'FakeStringValue' + Password = 'FakeStringValue' + } } - DisplayName = "FakeStringValue" - Id = "FakeStringValue" - TargetUrl = "FakeStringValue" } } } @@ -282,27 +235,15 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Mock -CommandName Get-MgBetaIdentityAPIConnector -MockWith { return @{ - AdditionalProperties = @{ - '@odata.type' = "#microsoft.graph.IdentityApiConnector" - } + DisplayName = 'FakeStringValue' + TargetUrl = 'FakeStringValue' + Id = 'FakeStringValue' AuthenticationConfiguration = @{ - '@odata.type' = "#microsoft.graph.basicAuthentication" - Pkcs12Value = "FakeStringValue" - Password = "FakeStringValue" - Username = "FakeStringValue" - CertificateList = @( - @{ - IsActive = $True - NotAfter = $True - Thumbprint = "FakeStringValue" - NotBefore = $True - } - ) + AdditionalProperties = @{ + Username = 'FakeStringValue' + Password = 'FakeStringValue' + } } - DisplayName = "FakeStringValue" - Id = "FakeStringValue" - TargetUrl = "FakeStringValue" - } } } From e089ba5629c0e19350b99fee4f7db00b1ea8d2bd Mon Sep 17 00:00:00 2001 From: "Kartikeya Saxena (from Dev Box)" Date: Wed, 23 Oct 2024 12:02:04 +0530 Subject: [PATCH 08/11] Adding more UTs --- ...ft365DSC.AADIdentityAPIConnector.Tests.ps1 | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADIdentityAPIConnector.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADIdentityAPIConnector.Tests.ps1 index 8fcde7f64b..d8484eef0b 100644 --- a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADIdentityAPIConnector.Tests.ps1 +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADIdentityAPIConnector.Tests.ps1 @@ -225,6 +225,60 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { } } + + Context -Name "The AADIdentityAPIConnector with certificates exists and values are in the desired state" -Fixture { + + BeforeAll { + $testParams = @{ + DisplayName = 'FakeStringValue' + TargetUrl = 'FakeStringValue' + Id = 'FakeStringValue' + Certificates = @( + New-CimInstance -ClassName 'MSFT_AADIdentityAPIConnectionCertificate' -Property @{ + Thumbprint = 'FakeStringValue' + Pkcs12Value = (New-CimInstance -ClassName 'MSFT_Credential' -Property @{ + Username = 'FakeStringValue' + Password = 'FakeStringValue' + } -ClientOnly) + Password = (New-CimInstance -ClassName 'MSFT_Credential' -Property @{ + Username = 'FakeStringValue' + Password = 'FakeStringValue' + } -ClientOnly) + IsActive = $true + } -ClientOnly + ) + Credential = $Credential + Ensure = 'Present' + } + + Mock -CommandName Get-MgBetaIdentityAPIConnector -MockWith { + return @{ + DisplayName = 'FakeStringValue' + TargetUrl = 'FakeStringValue' + Id = 'FakeStringValue' + AuthenticationConfiguration = @{ + AdditionalProperties = @{ + certificateList = @( + @{ + Thumbprint = 'FakeStringValue' + IsActive = $true + } + ) + } + } + } + } + } + + It 'Should return Values from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + + It 'Should return false from the Test method' { + Test-TargetResource @testParams | Should -Be $true + } + } + Context -Name 'ReverseDSC Tests' -Fixture { BeforeAll { $Global:CurrentModeIsExport = $true From d482791bbe1b8788fb8dd1dd7af226f70962c931 Mon Sep 17 00:00:00 2001 From: "Kartikeya Saxena (from Dev Box)" Date: Wed, 23 Oct 2024 12:25:51 +0530 Subject: [PATCH 09/11] Adding examples --- .../AADIdentityAPIConnector/1-Create.ps1 | 37 +++++++++++++++++++ .../AADIdentityAPIConnector/2-Update.ps1 | 37 +++++++++++++++++++ .../AADIdentityAPIConnector/3-Remove.ps1 | 37 +++++++++++++++++++ 3 files changed, 111 insertions(+) create mode 100644 Modules/Microsoft365DSC/Examples/Resources/AADIdentityAPIConnector/1-Create.ps1 create mode 100644 Modules/Microsoft365DSC/Examples/Resources/AADIdentityAPIConnector/2-Update.ps1 create mode 100644 Modules/Microsoft365DSC/Examples/Resources/AADIdentityAPIConnector/3-Remove.ps1 diff --git a/Modules/Microsoft365DSC/Examples/Resources/AADIdentityAPIConnector/1-Create.ps1 b/Modules/Microsoft365DSC/Examples/Resources/AADIdentityAPIConnector/1-Create.ps1 new file mode 100644 index 0000000000..7382692428 --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/AADIdentityAPIConnector/1-Create.ps1 @@ -0,0 +1,37 @@ +<# +This example is used to test new resources and showcase the usage of new resources being worked on. +It is not meant to use as a production baseline. +#> + +Configuration Example +{ + param( + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + node localhost + { + AADIdentityAPIConnector 'AADIdentityAPIConnector-TestConnector' + { + DisplayName = "NewTestConnector"; + Id = "RestApi_NewTestConnector"; + Username = "anexas"; + Password = New-Object System.Management.Automation.PSCredential('Password', (ConvertTo-SecureString "anexas" -AsPlainText -Force)); + TargetUrl = "https://graph.microsoft.com"; + Ensure = "Present" + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + } + } +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/AADIdentityAPIConnector/2-Update.ps1 b/Modules/Microsoft365DSC/Examples/Resources/AADIdentityAPIConnector/2-Update.ps1 new file mode 100644 index 0000000000..d123d0151f --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/AADIdentityAPIConnector/2-Update.ps1 @@ -0,0 +1,37 @@ +<# +This example is used to test new resources and showcase the usage of new resources being worked on. +It is not meant to use as a production baseline. +#> + +Configuration Example +{ + param( + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + node localhost + { + AADIdentityAPIConnector 'AADIdentityAPIConnector-TestConnector' + { + DisplayName = "NewTestConnector"; + Id = "RestApi_NewTestConnector"; + Username = "anexas 1"; #drift + Password = New-Object System.Management.Automation.PSCredential('Password', (ConvertTo-SecureString "anexas" -AsPlainText -Force)); + TargetUrl = "https://graph.microsoft.com"; + Ensure = "Present" + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + } + } +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/AADIdentityAPIConnector/3-Remove.ps1 b/Modules/Microsoft365DSC/Examples/Resources/AADIdentityAPIConnector/3-Remove.ps1 new file mode 100644 index 0000000000..926a36404f --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/AADIdentityAPIConnector/3-Remove.ps1 @@ -0,0 +1,37 @@ +<# +This example is used to test new resources and showcase the usage of new resources being worked on. +It is not meant to use as a production baseline. +#> + +Configuration Example +{ + param( + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + node localhost + { + AADIdentityAPIConnector 'AADIdentityAPIConnector-TestConnector' + { + DisplayName = "NewTestConnector"; + Id = "RestApi_NewTestConnector"; + Username = "anexas"; + Password = New-Object System.Management.Automation.PSCredential('Password', (ConvertTo-SecureString "anexas" -AsPlainText -Force)); + TargetUrl = "https://graph.microsoft.com"; + Ensure = "Absent" + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + } + } +} From b46b69e79d082349159ad729a77572e7ee720559 Mon Sep 17 00:00:00 2001 From: "Kartikeya Saxena (from Dev Box)" Date: Wed, 23 Oct 2024 14:28:10 +0530 Subject: [PATCH 10/11] Updating change log --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 756b3e9f19..235fb7d6f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ * Initial release. * AADIdentityGovernanceProgram * Initial release. +* AADIdentityAPIConnector + * Initial release. * SPOTenantSettings * Added support for AllowSelectSGsInODBListInTenant, DenySelectSGsInODBListInTenant, DenySelectSecurityGroupsInSPSitesList, From 0365d28af199e7e6405cc578242a22ce338d85c9 Mon Sep 17 00:00:00 2001 From: "Kartikeya Saxena (from Dev Box)" Date: Wed, 23 Oct 2024 16:27:15 +0530 Subject: [PATCH 11/11] Added Stub files --- Tests/Unit/Stubs/Microsoft365.psm1 | 264 +++++++++++++++++++++++++++++ 1 file changed, 264 insertions(+) diff --git a/Tests/Unit/Stubs/Microsoft365.psm1 b/Tests/Unit/Stubs/Microsoft365.psm1 index 7fc7c2ef08..0c9e839660 100644 --- a/Tests/Unit/Stubs/Microsoft365.psm1 +++ b/Tests/Unit/Stubs/Microsoft365.psm1 @@ -98721,4 +98721,268 @@ function Remove-MgBetaOrganizationCertificateBasedAuthConfiguration ) } +function Update-MgBetaIdentityApiConnector +{ + [CmdletBinding()] + param( + [Parameter()] + [System.String] + $DisplayName, + + [Parameter()] + [System.Collections.Hashtable] + $AuthenticationConfiguration, + + [Parameter()] + [System.String] + $IdentityApiConnectorId, + + [Parameter()] + [System.Collections.Hashtable] + $AdditionalProperties, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $ProxyUseDefaultCredentials, + + [Parameter()] + [PSObject] + $HttpPipelinePrepend, + + [Parameter()] + [System.String] + $TargetUrl, + + [Parameter()] + [PSObject] + $InputObject, + + [Parameter()] + [System.Uri] + $Proxy, + + [Parameter()] + [PSObject] + $BodyParameter, + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Confirm, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ProxyCredential, + + [Parameter()] + [System.String] + $ResponseHeadersVariable, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Break, + + [Parameter()] + [System.Collections.IDictionary] + $Headers, + + [Parameter()] + [PSObject] + $HttpPipelineAppend + ) +} + +function New-MgBetaIdentityApiConnector +{ + [CmdletBinding()] + param( + [Parameter()] + [System.String] + $DisplayName, + + [Parameter()] + [System.Collections.Hashtable] + $AuthenticationConfiguration, + + [Parameter()] + [System.Collections.Hashtable] + $AdditionalProperties, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $ProxyUseDefaultCredentials, + + [Parameter()] + [PSObject] + $HttpPipelinePrepend, + + [Parameter()] + [System.String] + $TargetUrl, + + [Parameter()] + [System.Uri] + $Proxy, + + [Parameter()] + [PSObject] + $BodyParameter, + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Confirm, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ProxyCredential, + + [Parameter()] + [System.String] + $ResponseHeadersVariable, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Break, + + [Parameter()] + [System.Collections.IDictionary] + $Headers, + + [Parameter()] + [PSObject] + $HttpPipelineAppend + ) +} + +function Remove-MgBetaIdentityApiConnector +{ + [CmdletBinding()] + param( + [Parameter()] + [PSObject] + $InputObject, + + [Parameter()] + [PSObject] + $HttpPipelinePrepend, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ProxyCredential, + + [Parameter()] + [System.Uri] + $Proxy, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $PassThru, + + [Parameter()] + [System.String] + $IfMatch, + + [Parameter()] + [System.String] + $ResponseHeadersVariable, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Confirm, + + [Parameter()] + [PSObject] + $HttpPipelineAppend, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $ProxyUseDefaultCredentials, + + [Parameter()] + [System.Collections.IDictionary] + $Headers, + + [Parameter()] + [System.String] + $IdentityApiConnectorId, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Break + ) +} + +function Invoke-MgBetaUploadIdentityApiConnectorClientCertificate +{ + [CmdletBinding()] + param( + [Parameter()] + [System.String] + $Password, + + [Parameter()] + [System.String] + $IdentityApiConnectorId, + + [Parameter()] + [System.Collections.Hashtable] + $AdditionalProperties, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $ProxyUseDefaultCredentials, + + [Parameter()] + [PSObject] + $HttpPipelinePrepend, + + [Parameter()] + [System.String] + $Pkcs12Value, + + [Parameter()] + [PSObject] + $InputObject, + + [Parameter()] + [System.Uri] + $Proxy, + + [Parameter()] + [PSObject] + $BodyParameter, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Confirm, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ProxyCredential, + + [Parameter()] + [System.String] + $ResponseHeadersVariable, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Break, + + [Parameter()] + [System.Collections.IDictionary] + $Headers, + + [Parameter()] + [PSObject] + $HttpPipelineAppend + ) +} + #endregion