ACMESharp icon indicating copy to clipboard operation
ACMESharp copied to clipboard

Add parameter to manual challenge handler to generate computer-friendly output

Open ebekker opened this issue 6 years ago • 13 comments

The manual Challenge Handler provider type outputs its computed results in a human-friendly format.

However, in order to make it useful for integrating into scripts, it would be more useful to support outputting a computer-friendly format, such as JSON or outputing a PSObject.

Some related issues:

  • #76
  • #125
  • #187

ebekker avatar Aug 02 '17 04:08 ebekker

The new bool parameter OutputJson has been added to the Manual Challenge Handler. If true, it will output all the same info as before, but as structured JSON. See the ref docs for more details.

A few typical use cases...

In this example, we output the JSON to a file in the current path, overwriting anything that may already be there:

PS> Complete-ACMEChallenge -IdentifierRef some-dns-alias -ChallengeType http-01 -Handler manual -HandlerParameters @{
>> WriteOutPath = "$PWD\manual-http-challenge.json"
>> Overwrite = $true
>> OutputJson = $true
>> }

Another example, where we first create a profile to capture our preferences, then use the profile and pipe it directly to a convert cmdlet and select the DNS Resource Record Value:

PS> Set-ACMEChallengeHandlerProfile -ProfileName manual-dns-json -ChallengeType dns-01 -Handler manual -HandlerParameters @{ OutputJson = $true }
PS> Complete-ACMEChallenge -IdentifierRef some-dns-alias -HandlerProfileRef manual-dns-json | ConvertFrom-JSON | select -Expand DnsDetails | select RRValue

ebekker avatar Aug 08 '17 15:08 ebekker

A sample output of an HTTP challenge with JSON:

{
  "Label": "Manual Challenge Handler - HTTP",
  "CleanUpTime": "2017-08-08T11:41:47.1072234-04:00",
  "ChallengeToken": "XpPNofCQvBJxuw3hs_sMb_I6SGVPgEPJD2_qE_LHGbA",
  "ChallengeType": "HTTP",
  "Description": [
    "The Challenge has been completed -- you can now remove the",
    "file created previously with the following characteristics:"
  ],
  "HttpDetails": {
    "HttpUrl": "http://test4.acmetesting.foo/.well-known/acme-challenge/XpPNofCQvBJxuw3hs_sMb_I6SGVPgEPJD2_qE_LHGbA",
    "FilePath": ".well-known/acme-challenge/XpPNofCQvBJxuw3hs_sMb_I6SGVPgEPJD2_qE_LHGbA",
    "FileContent": "XpPNofCQvBJxuw3hs_sMb_I6SGVPgEPJD2_qE_LHGbA.UVKRuns238-77zGmhhSICa2fofSbFUL9PpyHEMNokCI",
    "MimeType": "text/plain"
  }
}

Another sample, this time with DNS and the Clean Up operation:

{
  "Label": "Manual Challenge Handler - DNS",
  "CleanUpTime": "2017-08-08T11:33:42.4255157-04:00",
  "ChallengeToken": "fYwlkAlvduAg336jQlAnf6WnnmfkW7SAipGhWJpjt1w",
  "ChallengeType": "DNS",
  "Description": [
    "The Challenge has been completed -- you can now remove the",
    "Resource Record created previously with the following",
    "characteristics:"
  ],
  "DnsDetails": {
    "RRType": "TXT",
    "RRName": "_acme-challenge.test4.acmetesting.foo",
    "RRValue": "Uyh3aIv8e2U4r9rfaZdtbahL55OyCumcrvxZSIuidp0"
  }
}

ebekker avatar Aug 08 '17 15:08 ebekker

When I run the following command it returns an AuthorizationState object, not JSON. The AuthorizationState object doesn't appear to have the DnsDetails I'm looking for. Complete-ACMEChallenge some-alias -ChallengeType dns-01 -Handler manual -Regenerate -Repeat -HandlerParameters @{ OutputJson = $true }

1trevor avatar Aug 10 '17 16:08 1trevor

Hi 1trevor, which version of ACMESharp are you using? This feature was added to 0.9.0 which is not released as the main version yet -- it's only available in the early access feed. The new version will be updated to the main release soon.

ebekker avatar Aug 14 '17 11:08 ebekker

Hey there! I've got the same issue as @1trevor and I Just updated to the current version:

PS> Get-Module ACMESharp

ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Binary     0.9.0.321  ACMESharp                           {Complete-Challenge, Get-Certificate, Get-ChallengeHandlerProfile, Get-Identifier...}

Any ideas?

KuestenKeks avatar Sep 04 '17 15:09 KuestenKeks

It is as if you are writing to the host directly instead of the pipeline.

EagleIJoe avatar Sep 15 '17 10:09 EagleIJoe

@EagleIJoe It doesn't matter if you're writing it to a pipeline or not.

PS C:\ACMESharp> Complete-ACMEChallenge -IdentifierRef 1 -ChallengeType dns-01 -Handler manual -HandlerParameters @{ OutputJson = $true } -Repeat | ConvertFrom-Json | select -Expand DnsDetails | select RRValue
{
  "Label": "Manual Challenge Handler - DNS",
  "HandleTime": "2017-09-15T12:55:50.4853817+02:00",
  "ChallengeToken": "paiSFOxwq4qQ896Kacess62C-8PvdrRh1aizjoTAJe8",
  "ChallengeType": "DNS",
.
.
.
    "RRValue": "o1EGRGuONSMGmTXbZy1dY43ZiKYsPB-AOHwYk2JmAwE"
  }
}

ConvertFrom-Json : Invalid JSON primitive: ACMESharp.AuthorizationState.
At line:1 char:135
+ ... -HandlerParameters @{ OutputJson = $true } -Repeat | ConvertFrom-Json
+                                                          ~~~~~~~~~~~~~~~~                                                         
    + CategoryInfo          : NotSpecified: (:) [ConvertFrom-Json], ArgumentException
    + FullyQualifiedErrorId : System.ArgumentException,Microsoft.PowerShell.Commands.ConvertFromJsonCommand

bcs78 avatar Sep 15 '17 11:09 bcs78

@bcs78 I was not referring to us consumers of the code.

The JSON output is apparently writing directly to the console and not to the pipeline. That means, that ConvertFrom-Json does not even see that and rather gets pipped the object ACMESharp.AuthorizationState which in turn is not JSON, hence the error.

EagleIJoe avatar Sep 15 '17 11:09 EagleIJoe

@EagleIJoe Oh, I see, my bad. Anyway I hope this will be fixed soon.

bcs78 avatar Sep 15 '17 11:09 bcs78

Hmm, you guys are absolutely right -- I am writing to the standard output stream in the underlying challenge handler.

So the fundamental issue is that all of the providers and handlers are written to be PowerShell-agnostic -- that is they aren't aware that they're running in a PowerShell session (runspace), they are just there to support the core ACME client library that underlies the PS module. This is great if you're using the library in code that is not operating under PowerShell, like your own app.

But of course it has this major issue when it is running in PS. Prior to the 0.9.x series this wasn't a big deal as there really weren't any scenarios where the console output should have been effectively piped to PowerShell's standard output stream, but of course this is the exception.

ebekker avatar Sep 16 '17 01:09 ebekker

So to get most of you past this issue for now, you can set an optional WriteOutPath to redirect the output to a file. And then you can open and parse that file as JSON. It's a bit ugly for the case that some of you are trying to work with (piping and parson the JSON in PS directly), but it should get you over the hump until I implement a more permanent and correct fix.

ebekker avatar Sep 16 '17 01:09 ebekker

@ebekker thanks for the work around.

My suggestion is to add the output to the resulting object as a property. This property can then be piped to process it.

EagleIJoe avatar Sep 16 '17 10:09 EagleIJoe

@EagleIJoe -- the issue here is actually a bit more involved than that. The problem is that the Handler is writing its output directly to Console.Out (i.e. STDOUT of the host PowerShell.exe process). That completely bypasses all of the PowerShell plumbing for I/O and PS streams. I essentially need to reroute the underlying .NET console output to go to PowerShell output stream.

I would have thought this was something standard and typical, but in doing a bit of research and asking around in the last 12 hours, that doesn't seem to be the case, so I may need to do something special here, but I already have a couple ideas if nothing official pops up...

ebekker avatar Sep 16 '17 16:09 ebekker