wcf icon indicating copy to clipboard operation
wcf copied to clipboard

dotnet-svcutil - ability to ignore certficate error when generating code

Open johanskoldekrans opened this issue 2 years ago • 3 comments

Would like the ability to ignore certificate errors when generating c# from the command line tool. I have over a hundred WCF endpoints that I update through a powershell script for every version of a system we use and clicking accept for the certficate warnings would be nice to avoid with a switch to the tool.

johanskoldekrans avatar May 03 '22 07:05 johanskoldekrans

@johanskoldekrans does this behavior repro on .NET framework? If not, is it possible for you to share a simple repro with us?

HongGit avatar Jun 24 '22 03:06 HongGit

[CmdletBinding()]
Param(
    [switch]
    $BaseServices,

    [switch]
    $Services,

    [switch]
    $ValidationEngineServices
)

function Write-Bar()
{
    Write-Host
    Write-Host "******************************************************" -ForegroundColor White
    Write-Host
}

function Generate-Services($serviceCategory)
{
    $serviceListFilePath = "$PSScriptRoot/_ServiceLists/"

    Switch ($serviceCategory)
    {
        "BaseServices"
        {
            $serviceListFilePath += "BaseServiceList.txt"
            $baseUrl = "https://198.193.172.57/AbaSecServicesEPB"
        }
        "Services"
        {
            $serviceListFilePath += "ServiceList.txt";
            $baseUrl = "https://198.193.172.57/AbaSecuritiesServicesEPB"
        }
        "ValidationEngineServices"
        {
            $serviceListFilePath += "ValidationEngineServiceList.txt"
            $baseUrl = "https://198.193.172.57/ValidationEngineServicesEPB"
        }
        default
        {
            throw "Invalid service category: '$serviceCategory'"
        }
    }

    $servicesFileContent = Get-Content -Path $serviceListFilePath
    $servicesFolderPath = "$PSScriptRoot/$serviceCategory"
    $stagingFileName = "_CurrentService.cs"

    Write-Bar

    $counter = 0
    $successfulCounter = 0;
    $failedServices = @();

    $services = @()

    # Exclude commented lines or part of lines, '#' is used as a commenting character
    $servicesFileContent | ForEach-Object {
        $serviceName = $_.Split('#')[0].Trim()
        if (($null -ne $serviceName) -and ($serviceName -ne '')) { $services += $serviceName }
    }

    $services | ForEach-Object {
        $counter++

        $serviceName = $_
        $serviceUrl = "$baseUrl/$serviceName`?wsdl"

        if ($serviceName.EndsWith('.svc'))
        {
            $serviceName = $serviceName.Substring(0, $serviceName.Length-4)
        }

        Write-Host "Generating code for service: " -NoNewline
        Write-Host $serviceName -ForegroundColor Cyan -NoNewline
        Write-Host " ($counter/$($services.Length))"
        Write-Host

        if (Test-Path "$servicesFolderPath/$stagingFileName")
        {
            Remove-Item $servicesFolderPath/$stagingFileName -Force
        }

        $cmdLine = "dotnet svcutil $serviceUrl --outputFile $stagingFileName --outputDir $servicesFolderPath --namespace *,AbaSecService.$serviceCategory.$serviceName"

        Write-Host "Executing command: "
        Write-Host $cmdLine -ForegroundColor Cyan
        Write-Host

        Invoke-Expression $cmdLine

        if ($LASTEXITCODE -ne 0)
        {
            Write-Host
            Write-Host "Failed to generate service!" -ForegroundColor Red
            Write-Bar

            $failedServices += $serviceName

            return
        }

        $stagingFilePath = "$servicesFolderPath/$stagingFileName"
        $destinationFilePath = "$servicesFolderPath/$serviceName.cs"

        Write-Host "Renaming " -NoNewline
        Write-Host $stagingFilePath -ForegroundColor Cyan -NoNewline
        Write-Host " to " -NoNewline
        Write-Host $destinationFilePath -ForegroundColor Cyan

        Move-Item -Path $stagingFilePath -Destination $destinationFilePath -Force
        Write-Host
        Write-Host "Successfully generated service!" -ForegroundColor Green
        Write-Bar

        $successfulCounter += 1
    }

    Remove-Item "$servicesFolderPath/dotnet-svcutil.params.json" -Force

    Write-Host "Successfully generated $successfulCounter out of $counter services" -ForegroundColor Green
    Write-Host

    if ($failedServices.Length -gt 0)
    {
        "The following services could not be generated:"
        $failedServices | ForEach-Object {
            Write-Host $_ -ForegroundColor Red
        }
    }

    Write-Host
}

Push-Location $PSScriptRoot

dotnet tool install --global dotnet-svcutil
$startTime = [System.Diagnostics.Stopwatch]::StartNew()

$anyAction = $false

if ($Services)
{
    Generate-Services("Services")
    $anyAction = $true
}
if ($BaseServices)
{
    Generate-Services("BaseServices")
    $anyAction = $true
}
if ($ValidationEngineServices)
{
    Generate-Services("ValidationEngineServices")
    $anyAction = $true
}

if (-not $anyAction)
{
    $scriptName = $MyInvocation.MyCommand.Name
    Write-Host "Please specify which service category to generate.`n"
    Write-Host "Example: $scriptName -BaseServices -Services -ValidationEngineServices`n"
    throw "Error"
}

$elapsedTime = $startTime.Elapsed
Write-Host "Elapsed time: " -NoNewline
Write-Host $([string]::Format("{0:d2}:{1:d2}:{2:d2}",
                        $elapsedTime.hours,
                        $elapsedTime.minutes,
                        $elapsedTime.seconds)) -ForegroundColor Magenta
Write-Host

Pop-Location

Above is the powershell we are using. Below is what I am trying to avoid image

johanskoldekrans avatar Jun 27 '22 09:06 johanskoldekrans

I can think of a couple of potential workarounds.

Presuming you are connecting to WCF servers (because of the check for .svc) you could use the ?singleWsdl url method to download the wsdl as a single file. In powershell, download the wsdl to disk and then pass that to dotnet-svcutil. As you are downloading the file yourself, you have control over certificate. This has the downside that you won't be able to simply tell dotnet-svcutil to update the generated client if there's wsdl changes as it will have recorded that the wsdl url is on disk.

Alternatively you could save the server certificate to the Trusted People store temporarily and then they will be trusted by HttpClient that dotnet-svcutil uses. The downside to this is if something goes wrong running your script, you could end up leaving the certificates in the trusted people store. This is potentially a security risk depending on how much you trust the servers and the control of the private key.

@HongGit, he's only asking for a command line parameter to be able to pre-answer the question that you trust the servers certificate so that he doesn't need to be sitting in front of the script as it runs and hit enter each time.

mconnew avatar Jun 27 '22 21:06 mconnew

A fix of the reported issue has been released, a brief description of the fix usage is showed below as a reference, you can install the latest version of dotnet-svcutil from nuget.org, type "dotnet svcutil -h" for more details and try it out.

--acceptCertificate    - Accept remote certificate as trusted when downloading service metadata. (Short
                                            Form: -ac)

imcarolwang avatar Nov 01 '22 07:11 imcarolwang