Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
In order to test it, you need to get vsphere SDK for webservices, as this is using the libraries from it.
new-webserviceproxy can't handle soap security headers. You also need PKCS#12 pfx certificate (in my example)
Function ConvertTo-GZipString () {
[Parameter(Mandatory = $True, ValueFromPipeline = $True, ValueFromPipelinebyPropertyName = $True)]
Process {
$String | ForEach-Object {
$stream = [System.IO.MemoryStream]::new()
$writer = [System.IO.StreamWriter][System.IO.Compression.GZipStream]::new($stream, [System.IO.Compression.CompressionMode]::Compress)
Add-Type -Path 'd:\vsphereWebServicesSDK67\ssoclient\dotnet\cs\samples\VMware.Binding.WsTrust\bin\Debug\VMware.Binding.WsTrust.dll'
Add-Type -Path 'd:\vsphereWebServicesSDK67\ssoclient\dotnet\cs\samples\VMware.Binding.WsTrust\bin\Debug\STSService.dll'
$certificatetobeadded = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
#i have generated my certificate with 'greg3' password
$certificatetobeadded.Import('d:\vro\greg\greg3.pfx', 'greg3', [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::MachineKeySet)
#[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls11 -bor [System.Net.SecurityProtocolType]::Tls12;
$signingCertificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$signingCertificate.Import('d:\vro\greg\greg3.pfx', 'greg3', [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::MachineKeySet)
$service = [VMware.Binding.WsTrust.SamlTokenHelper]::GetSTSService('https://vc001.greg.labs:7444/sts/STSService', 'administrator@vsphere.local', 'VMware1!', $signingCertificate)
$token = [VMware.Binding.WsTrust.SamlTokenHelper]::GetHokRequestSecurityTokenType()
$token.SignatureAlgorithm = [vmware.sso.SignatureAlgorithmEnum]::httpwwww3org200104xmldsigmorersasha256
$response = $service.Issue($token)
$responsetoken = $response.RequestSecurityTokenResponse.RequestedSecurityToken
$responsetokenXML = $responsetoken.OuterXml
$encodedANDgzippedtoken = ConvertTo-GZipString -String $responsetokenXML
#I had new line like that before but `n works as well.
#$nl = (0x0A -as [char])
$restmethod = 'GET'
$timestamp = [DateTimeOffset]::Now.ToUnixTimeSeconds().ToString()
$nonce = $timestamp + ':ass234'
[system.uri]$uri = 'https://vro816.greg.labs:443/vco/api/org/{id}/workflows?maxResult=3&queryCount=false'
$httprequesturi = '/' + $uri.AbsolutePath.split('/')[-1] + $uri.Query
$httprequesthost = $uri.Host
$httprequestport = $uri.Port
$noext = ''
$normalizedrequeststring = $timestamp + "`n" + $nonce + "`n" + $timestamp + "`n" + $restmethod + "`n" + $httprequesturi + "`n" + $httprequesthost + "`n" + $httprequestport + "`n" + $noext + "`n"
$popt = [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable
$psigningCertificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$psigningCertificate.Import('d:\vro\greg\greg3.pfx', 'greg3', $popt)
#converted from c# to PS from
$privatekey = $psigningCertificate.PrivateKey
$privatekey1 = New-Object System.Security.Cryptography.RSACryptoServiceProvider
$enc = [system.Text.Encoding]::UTF8
$data = $enc.GetBytes($normalizedrequeststring)
$sig = $privatekey1.SignData($data, "SHA256")
$base64sig = [Convert]::ToBase64String($sig)
#[bool]$isValid = $privateKey1.VerifyData($data, "SHA256", $sig)
$headervalue = 'SIGN token="{0}",nonce="{1}",signature_alg="RSA-SHA256",signature="{2}"' -f $encodedANDgzippedtoken, $nonce, $base64sig
$header = @{'Authorization' = $headervalue }
$answer = Invoke-WebRequest -Uri 'https://vro816.greg.labs:443/vco/api/org/{id}/workflows?maxResult=3&queryCount=false' -Headers $header
Write it natively so that there is no need to load dlls from sdk.
Please find the details below shared by the engineering team.
The Authorization header has the following.
Authorization: SIGN token="...",
token REQUIRED. The SAML2 token identifying the caller. The value is calculated as BASE64(GZIP(SAML2)).
nonce REQUIRED. A unique string generated by the client allowing the server to identify replay attacks and reject such requests.
The strings must be unique across all requests of a single client. The definition is as specified in Section 3.1
of draft-ietf-oauth-v2-http-mac ( with one difference - the first component should be the current time expressed in
the number of milliseconds since January 1, 1970 00:00:00 GMT with no leading zeros.
bodyhash OPTIONAL. A hash value computed as described in Section 3.2 of draft-ietf-oauth-v2-http-mac ( over the entire HTTP request
entity body (as defined in Section 7.2 of RFC 2616( Note that the body hash may be missing only if there is no
request body, i.e. empty body. Otherwise it is required.
signature_alg REQUIRED. The signature algorithm used by the client to sign the request - "RSA-SHA256", "RSA-SHA384" and "RSA-SHA512"
signature REQUIRED. A message signature calculated over the normalized request as
BASE64(signature-algorithm(private key, request)). The request normalization is done
as defined in Section 3.3.1 of draft-ietf-oauth-v2-http-mac ( with two exception - (a) the body hash is included without
BASE64 applied and (b) no "ext" field is appended. All text based fields in the normalized request
are encoded in UTF-8.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment