Framework/Core/SVT/Services/APIConnection.ps1
Set-StrictMode -Version Latest class APIConnectionControl { [string] $Name = "" [string] $Automated = "" [string] $MethodName = "" [string] $Remarks = "" } class APIConnectionApprovedConnector { [string] $connectorName = "" [APIConnectionControl[]] $ApplicableControls = @() [APIConnectionControl[]] $NotApplicableControls = @() } class APIConnectionNotApprovedConnector { [string] $connectorName = "" [string] $Remarks = "" } class APIConnectionConnectorsMetadata { [APIConnectionApprovedConnector[]] $ApprovedConnectors = @() [APIConnectionNotApprovedConnector[]] $notApprovedConnectors = @() } class APIConnection: AzSVTBase { hidden [PSObject] $LogicAppObject; hidden [PSObject] $ResourceObject; hidden [APIConnectionConnectorsMetadata] $LogicAppConnectorsMetadata APIConnection([string] $subscriptionId, [SVTResource] $svtResource): Base($subscriptionId, $svtResource) { $this.GetResourceObject(); $this.LogicAppConnectorsMetadata = [APIConnectionConnectorsMetadata] ($this.LoadServerConfigFile("LogicApps.Connectors.json")); } hidden [PSObject] GetResourceObject() { $logicAppConnectors = $this.ResourceContext.ResourceName.Split("//") if(($logicAppConnectors | Measure-Object).count -eq 2) { $this.LogicAppObject = Get-AzResource -Name $logicAppConnectors[0] ` -ResourceGroupName $this.ResourceContext.ResourceGroupName -ResourceType 'Microsoft.Logic/Workflows' } else { throw ([SuppressedException]::new(("Logic App Connector '{0}' not found under Resource Group '{1}'" -f ($this.ResourceContext.ResourceName), ($this.ResourceContext.ResourceGroupName)), [SuppressedExceptionType]::InvalidOperation)) } if (-not $this.LogicAppObject) { throw ([SuppressedException]::new(("LogicApp '{0}' not found under Resource Group '{1}'" -f ($this.ResourceContext.ResourceName), ($this.ResourceContext.ResourceGroupName)), [SuppressedExceptionType]::InvalidOperation)) } else { $this.ResourceObject = $this.GetConnectorObject() } return $this.ResourceObject; } hidden [PSObject] GetConnectorObject() { if($this.ResourceContext.ResourceId -like "*/custom/*") { $Definition = $this.LogicAppObject.Properties.definition if($null -ne $Definition.Actions -and -not[string]::IsNullOrEmpty($this.LogicAppObject.Properties.definition.actions)) { $connectorFound = ($Definition.Actions | Get-Member -MemberType *Property | Where-Object { $_.name -eq ($this.ResourceContext.ResourceName.Split("//")[1]) -and ($Definition.Actions.($_.name).type -ne 'ApiConnection') } | Select-Object -First 1) if($null -ne $connectorFound) { $Name = $connectorFound.name $Connector = New-Object PSObject Add-Member -InputObject $Connector -MemberType NoteProperty -Name ConnectorName -Value $Name Add-Member -InputObject $Connector -MemberType NoteProperty -Name ConnectorType -Value $Definition.Actions.$Name.type Add-Member -InputObject $Connector -MemberType NoteProperty -Name ConnectorObj -Value $Definition.Actions.$Name $this.ResourceObject = $Connector } } if($null -ne $Definition.triggers -and -not[string]::IsNullOrEmpty($this.LogicAppObject.Properties.definition.triggers)) { $connectorFound = ($Definition.Triggers | Get-Member -MemberType *Property | Where-Object { $_.name -eq ($this.ResourceContext.ResourceName.Split("//")[1]) -and ($Definition.Triggers.($_.name).type -ne 'ApiConnection') } | Select-Object -First 1) if($null -ne $connectorFound) { $Name = $connectorFound.name $Connector = New-Object PSObject Add-Member -InputObject $Connector -MemberType NoteProperty -Name ConnectorName -Value $Name Add-Member -InputObject $Connector -MemberType NoteProperty -Name ConnectorType -Value $Definition.Triggers.$Name.type Add-Member -InputObject $Connector -MemberType NoteProperty -Name ConnectorObj -Value $Definition.Triggers.$Name $this.ResourceObject = $Connector } } } else { $apiConObj = Get-AzResource -ResourceId $this.ResourceContext.ResourceId $apiName=$apiConObj.Properties.Api.Name $Connector = New-Object PSObject Add-Member -InputObject $Connector -MemberType NoteProperty -Name ConnectorName -Value $apiName Add-Member -InputObject $Connector -MemberType NoteProperty -Name ConnectorType -Value $apiName Add-Member -InputObject $Connector -MemberType NoteProperty -Name ConnectorObj -Value $null $this.ResourceObject = $Connector } return $this.ResourceObject; } hidden [ControlResult] CheckConnectorsAADAuth([ControlResult] $controlResult) { $controlResult = $this.GetConnectorsStatus("AAD", $controlResult) return $controlResult; } hidden [ControlResult] CheckConnectorsEncryptionInTransit([ControlResult] $controlResult) { $controlResult = $this.GetConnectorsStatus("EncryptionTransit", $controlResult) return $controlResult; } #internal functions hidden [ControlResult] CheckAadAuthForHttp([string] $remarks , [ControlResult] $childControlResult) { $isPassed = $false if(Get-Member -inputobject $this.ResourceObject.ConnectorObj.inputs -name "authentication" -Membertype Properties) { if([Helpers]::CheckMember($this.ResourceObject.ConnectorObj.inputs.authentication,"type") -and $this.ResourceObject.ConnectorObj.inputs.authentication.type -eq "ActiveDirectoryOAuth") { $isPassed = $true } } if($isPassed) { $childControlResult.AddMessage([VerificationResult]::Passed,"AAD Authentication is used in connector - "+ $this.ResourceObject.ConnectorName) } else { $childControlResult.AddMessage([VerificationResult]::Failed, "AAD Authentication is not used in connector - "+ $this.ResourceObject.ConnectorName) } return $childControlResult } hidden [ControlResult] CheckEncryptionTransitForHttp([string] $remarks, [ControlResult] $childControlResult) { $isPassed = $true if(([Helpers]::CheckMember($this.ResourceObject.connectorObj.inputs,"uri"))) { $uriString = $this.ResourceObject.ConnectorObj.inputs.uri if(([system.Uri]$uriString).Scheme -ne 'https') { $isPassed = $false } if($isPassed) { $childControlResult.AddMessage([VerificationResult]::Passed,"Connector name : " + $this.ResourceObject.ConnectorName + "`r`nConnector URI : "+ $uriString) } else { $childControlResult.AddMessage([VerificationResult]::Failed, ` "Must use HTTPS URI for below connector`r`n" ` + "Connector name : " + $this.ResourceObject.ConnectorName + "`r`nConnector URI : "+$uriString) } } return $childControlResult } hidden [ControlResult] CheckEncryptionTransitForWebhook([string] $remarks , [ControlResult] $childControlResult) { $isPassed = $true $subURI = "" $unSubURI = "" if(([Helpers]::CheckMember($this.ResourceObject.connectorObj.inputs,"subscribe")) -and ([Helpers]::CheckMember($this.ResourceObject.connectorObj.inputs.subscribe,"uri"))) { $subURI = $this.ResourceObject.connectorObj.inputs.subscribe.uri } if(([Helpers]::CheckMember($this.ResourceObject.connectorObj.inputs,"unsubscribe")) -and ([Helpers]::CheckMember($this.ResourceObject.connectorObj.inputs.unsubscribe,"uri"))) { $unSubURI = $this.ResourceObject.connectorObj.inputs.unsubscribe.uri } if(($subURI -ne "" -and ([system.Uri]$subURI).Scheme -ne 'https') -or ($unSubURI -ne "" -and ([system.Uri]$unSubURI).Scheme -ne 'https')) { $isPassed = $false } if($isPassed) { $childControlResult.AddMessage([VerificationResult]::Passed, "Connector name : " + $this.ResourceObject.ConnectorName ` + "`r`nWebhook subscribe URI : "+ $subURI` + "`r`nWebhook unsubscribe URI : "+$unSubURI) } else { $childControlResult.AddMessage([VerificationResult]::Failed, "Must use HTTPS URI(s) for below connector`r`n" ` + "Connector name : " + $this.ResourceObject.ConnectorName ` + "`r`nWebhook subscribe URI : "+ $subURI` + "`r`nWebhook unsubscribe URI : "+$unSubURI) } return $childControlResult } hidden [ControlResult] GetConnectorsStatus([string] $controlName, [ControlResult] $controlResult) { $connectorName=$this.ResourceObject.ConnectorName $ConnectorObj = $this.ResourceObject.ConnectorObj $connectorType=$this.ResourceObject.ConnectorType if($connectorName -eq "manual") { $connectorName = $connectorType } #check if this connector belongs to not approved list $notApprovedConnector = $this.LogicAppConnectorsMetadata.NotApprovedConnectors | Where-Object {$_.connectorName -eq $connectorType} if($notApprovedConnector) { $controlResult.AddMessage([VerificationResult]::Failed, $notApprovedConnector.Remarks) } else { #Check if it belongs to approved connectors $approvedConnector = $this.LogicAppConnectorsMetadata.ApprovedConnectors | Where-Object {$_.connectorName -eq $connectorType} if(($approvedConnector|Measure-Object).Count -gt 0) { #check if control is applicable on this connector $applicableControl = $approvedConnector.ApplicableControls | Where-Object {$_.Name -eq $controlName} $notApplicableControl = $approvedConnector.NotApplicableControls | Where-Object {$_.Name -eq $controlName} if(($applicableControl|Measure-Object).Count -gt 0) { #Get method name $methodName = $applicableControl.MethodName $controlResult = $this.$methodName($applicableControl.Remarks , $controlResult) } else { $methodName = $notApplicableControl.MethodName if($notApplicableControl.Remarks -eq [string]::Empty) { $notApplicableControl.Remarks = "This control is not applicable on connector type - " + $connectorType } $controlResult = $this.$methodName($notApplicableControl.Remarks , $controlResult) } } else { $controlResult.AddMessage([VerificationResult]::Manual, $connectorType+" connector is not evaluated yet") } } return $controlResult } hidden [ControlResult] DefaultPassed([string] $remarks,[ControlResult] $childControlResult) { $childControlResult.AddMessage([VerificationResult]::Passed, $remarks) return $childControlResult } hidden [ControlResult] DefaultManual([string] $remarks,[ControlResult] $childControlResult) { $childControlResult.AddMessage([VerificationResult]::Manual, $remarks) return $childControlResult } } |