mirror of
https://github.com/Gerenios/AADInternals
synced 2026-06-08 11:09:38 +00:00
804 lines
32 KiB
PowerShell
804 lines
32 KiB
PowerShell
# This file contains utility functions related to Microsoft App Proxy
|
|
|
|
|
|
# Get's bootstrap configuration
|
|
# Apr 2nd 2020
|
|
function Get-BootstrapConfiguration
|
|
{
|
|
[cmdletbinding()]
|
|
Param(
|
|
[Parameter(Mandatory=$True)]
|
|
[String]$MachineName,
|
|
[Parameter(Mandatory=$False)]
|
|
[String]$ServiceHost="bootstrap.msappproxy.net",
|
|
[Parameter(Mandatory=$True)]
|
|
[System.Security.Cryptography.X509Certificates.X509Certificate2]$Certificate
|
|
)
|
|
Process
|
|
{
|
|
|
|
# Get the tenant id and instance id from the certificate
|
|
$TenantId = $Certificate.Subject.Split("=")[1]
|
|
$InstanceID = [guid]$Certificate.GetSerialNumberString()
|
|
|
|
# Actually, it is not the serial number but this oid for Private Enterprise Number. Microsoft = 1.3.6.1.4.1.311
|
|
foreach($extension in $cert.Extensions)
|
|
{
|
|
if($extension.Oid.Value -eq "1.3.6.1.4.1.311.82.1")
|
|
{
|
|
$InstanceID = [guid]$extension.RawData
|
|
}
|
|
}
|
|
|
|
$OSLanguage="1033"
|
|
$OSLocale="0409"
|
|
$OSSku="8"
|
|
$OSVersion="10.0.17763"
|
|
$AgentSdkVersion="1.5.1318.0"
|
|
$AgentVersion="1.1.96.0"
|
|
|
|
$body=@"
|
|
<BootstrapRequest xmlns="http://schemas.datacontract.org/2004/07/Microsoft.ApplicationProxy.Common.SignalerDataModel" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
|
|
<AgentSdkVersion>$AgentSdkVersion</AgentSdkVersion>
|
|
<AgentVersion>$AgentVersion</AgentVersion>
|
|
<BootstrapDataModelVersion>$AgentSdkVersion</BootstrapDataModelVersion>
|
|
<ConnectorId>$InstanceId</ConnectorId>
|
|
<ConnectorVersion>$AgentSdkVersion</ConnectorVersion>
|
|
<ConsecutiveFailures>0</ConsecutiveFailures>
|
|
<CurrentProxyPortResponseMode>Primary</CurrentProxyPortResponseMode>
|
|
<FailedRequestMetrics xmlns:a="http://schemas.datacontract.org/2004/07/Microsoft.ApplicationProxy.Common.BootstrapDataModel"/>
|
|
<InitialBootstrap>true</InitialBootstrap>
|
|
<IsProxyPortResponseFallbackDisabledFromRegistry>true</IsProxyPortResponseFallbackDisabledFromRegistry>
|
|
<LatestDotNetVersionInstalled>461814</LatestDotNetVersionInstalled>
|
|
<MachineName>$machineName</MachineName>
|
|
<OperatingSystemLanguage>$OSLanguage</OperatingSystemLanguage>
|
|
<OperatingSystemLocale>$OSLocale</OperatingSystemLocale>
|
|
<OperatingSystemSKU>$OSSku</OperatingSystemSKU>
|
|
<OperatingSystemVersion>$OSVersion</OperatingSystemVersion>
|
|
<PerformanceMetrics xmlns:a="http://schemas.datacontract.org/2004/07/Microsoft.ApplicationProxy.Common.BootstrapDataModel"/>
|
|
<ProxyDataModelVersion>$AgentSdkVersion</ProxyDataModelVersion>
|
|
<RequestId>$((New-Guid).ToString())</RequestId>
|
|
<SubscriptionId>$TenantId</SubscriptionId>
|
|
<SuccessRequestMetrics xmlns:a="http://schemas.datacontract.org/2004/07/Microsoft.ApplicationProxy.Common.BootstrapDataModel"/>
|
|
<TriggerErrors/>
|
|
<UpdaterStatus>Running</UpdaterStatus>
|
|
<UseServiceBusTcpConnectivityMode>false</UseServiceBusTcpConnectivityMode>
|
|
<UseSpnegoAuthentication>false</UseSpnegoAuthentication>
|
|
</BootstrapRequest>
|
|
"@
|
|
|
|
$url="https://$TenantId.$ServiceHost/ConnectorBootstrap"
|
|
|
|
try
|
|
{
|
|
$response = Invoke-WebRequest -UseBasicParsing -Uri $url -Method Post -Certificate $Certificate -Body $body -ContentType "application/xml; charset=utf-8"
|
|
}
|
|
catch
|
|
{
|
|
Write-Error "Could not get bootstrap: $($_.Exception.Message). Probably expired certificate ($($Certificate.Thumbprint)) or invalid agent ($InstanceID)?"
|
|
return $null
|
|
}
|
|
|
|
[xml]$xmlResponse = $response.Content
|
|
|
|
return $xmlResponse.OuterXml
|
|
|
|
|
|
}
|
|
}
|
|
|
|
# Creates a CSR from the scratch
|
|
# Apr 2nd 2020
|
|
function NewCSRforSync
|
|
{
|
|
[cmdletbinding()]
|
|
Param(
|
|
[Parameter(Mandatory=$True)]
|
|
[String]$MachineName,
|
|
[Parameter(Mandatory=$True)]
|
|
[byte[]]$PublicKey
|
|
)
|
|
process
|
|
{
|
|
$osVersion="6.2.9200.2"
|
|
$ADadminUser ="NotYourBusiness!!"
|
|
$exeName = "AADConnectProvisioningAgentWizard.exe"
|
|
|
|
|
|
$pksha1=[System.Security.Cryptography.SHA1CryptoServiceProvider]::new().ComputeHash($PublicKey)
|
|
|
|
# Construct the CSR for signin
|
|
$CSRToBeSigned=@(
|
|
Add-DERSequence -Data @(
|
|
Add-DERInteger -Data 0
|
|
0x30, 0x00
|
|
Add-DERSequence -Data @(
|
|
Add-DERSequence -Data @(
|
|
Add-DERTag -Tag 0x06 -Data @( # Object Identifier
|
|
# rsaEncryption (1.2.840.113549.1.1.1)
|
|
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01
|
|
)
|
|
0x05, 0x00 # Null
|
|
)
|
|
Add-DERTag -Tag 0x03 -Data @( # BitString
|
|
0x00
|
|
$PublicKey
|
|
)
|
|
|
|
)
|
|
|
|
Add-DERTag -Tag 0xA0 -Data @( # Context specific (block #0)
|
|
|
|
# Attributes: osVersion
|
|
Add-DERSequence -Data @(
|
|
|
|
Add-DERTag -Tag 0x06 -Data @( # Object Identifier
|
|
# osVersion (1.3.6.1.4.1.311.13.2.3)
|
|
0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x0D, 0x02, 0x03
|
|
)
|
|
Add-DERSet -Data @( # SET
|
|
Add-DERIA5String -Text $osVersion
|
|
)
|
|
)
|
|
|
|
# Extension Request
|
|
Add-DERSequence -Data @(
|
|
Add-DERTag -Tag 0x06 -Data @( # Object Identifier
|
|
# extensionRequest (1.2.840.113549.1.9.14)
|
|
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x0E
|
|
)
|
|
Add-DERSet -Data @(
|
|
Add-DERSequence -Data @(
|
|
|
|
# Key Usage
|
|
Add-DERSequence -Data @(
|
|
Add-DERTag -Tag 0x06 -Data @( # Object Identifier
|
|
0x55, 0x1D, 0x0F # keyUsage (2.5.29.15)
|
|
)
|
|
Add-DERTag 0x01 -Data @(0xFF) # Boolean (true)
|
|
Add-DERTag 0x04 -Data @(0x03, 0x02, 0x04, 0xF0) # Octet string
|
|
)#
|
|
# Ext Key Usage
|
|
Add-DERSequence -Data @(
|
|
Add-DERTag -Tag 0x06 -Data @( # Object Identifier
|
|
0x55, 0x1D, 0x25 # extKeyUsage (2.5.29.37)
|
|
)
|
|
Add-DERTag 0x04 -Data @(
|
|
Add-DERSequence -Data @(
|
|
Add-DERTag -Tag 0x06 -Data @( # Object Identifier
|
|
0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02 # clientAuth (1.3.6.1.5.5.7.3.2)
|
|
)
|
|
|
|
)
|
|
)
|
|
)
|
|
|
|
# Subject Key Identifier
|
|
Add-DERSequence -Data @(
|
|
Add-DERTag -Tag 0x06 -Data @( # subjectKeyIdentifier (2.5.29.14)
|
|
0x55, 0x1D, 0x0E
|
|
)
|
|
Add-DERTag 0x04 -Data @( # Octet string
|
|
0x04, 0x14#, 0xEB, 0x4F, 0xD9, 0xFF, 0x3A, 0x20, 0xA9, 0xDB, 0x63, 0xBA, 0x50, 0x2A, 0xF1, 0x5B, 0x96, 0x5F, 0x5C, 0x3C, 0xCD, 0xF4
|
|
$pksha1
|
|
)
|
|
)
|
|
|
|
|
|
)
|
|
)
|
|
)
|
|
|
|
# Request Client Info
|
|
Add-DERSequence -Data @(
|
|
Add-DERTag -Tag 0x06 -Data @( # Object Identifier
|
|
# requestClientInfo (1.3.6.1.4.1.311.21.20)
|
|
0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x15, 0x14
|
|
)
|
|
Add-DERSet -Data @( # Set
|
|
Add-DERSequence -Data @(
|
|
Add-DERInteger -Data 0x05
|
|
Add-DERUtf8String -Tag 0x0C -Text $machineName
|
|
Add-DERUtf8String -Tag 0x0C -Text $ADadminUser
|
|
Add-DERUtf8String -Tag 0x0C -Text $exeName
|
|
)
|
|
)
|
|
|
|
)
|
|
|
|
# Enrolment CSP
|
|
Add-DERSequence -Data @(
|
|
Add-DERTag -Tag 0x06 -Data @( # Object Identifier
|
|
# enrolmentCSP (1.3.6.1.4.1.311.13.2.2)
|
|
0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x0D, 0x02, 0x02
|
|
)
|
|
Add-DERSet -Data @(
|
|
Add-DERSequence -Data @(
|
|
Add-DERInteger 0x01
|
|
Add-DERUnicodeString -Tag 0x1E "Microsoft Enhanced RSA and AES Cryptographic Provider" -LE
|
|
Add-DERTag -Tag 0x03 -Data 0x00 # Bit string
|
|
)
|
|
)
|
|
)
|
|
|
|
)
|
|
)
|
|
|
|
)
|
|
|
|
# Sign the CSR
|
|
$signature = $rsa.SignData($CSRToBeSigned, [System.Security.Cryptography.HashAlgorithmName]::SHA256,[System.Security.Cryptography.RSASignaturePadding]::Pkcs1)
|
|
|
|
# Construct the CSR
|
|
$CSR = Add-DERSequence -Data @(
|
|
$CSRToBeSigned
|
|
Add-DERSequence -Data @(
|
|
Add-DERTag -Tag 0x06 -Data @(
|
|
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B
|
|
)
|
|
0x05, 0x00 # null
|
|
)
|
|
Add-DERTag -Tag 0x03 -Data @(
|
|
0x00
|
|
$signature
|
|
)
|
|
|
|
)
|
|
# return
|
|
|
|
return $CSR
|
|
}
|
|
}
|
|
|
|
# Connects to the given bus
|
|
function Connect-ToBus
|
|
{
|
|
[cmdletbinding()]
|
|
Param(
|
|
[Parameter(Mandatory=$True)]
|
|
[PSObject]$BootStrap,
|
|
[Parameter(Mandatory=$False)]
|
|
[System.Security.Cryptography.X509Certificates.X509Certificate2]$cert
|
|
)
|
|
Process
|
|
{
|
|
# Import AMQP.ps1
|
|
. "$PSScriptRoot\AMQP.ps1"
|
|
|
|
# Define AMQP messages
|
|
[byte[]]$AMQP0 = @(
|
|
0x41, 0x4D, 0X51, 0X50, # AMQP
|
|
0x00, # Protocol
|
|
0x01, # Major
|
|
0x00, # Minor
|
|
0x00) # Revision
|
|
|
|
[byte[]]$AMQP1 = @(
|
|
0x41, 0x4D, 0X51, 0X50, # AMQP
|
|
0x01, # Protcol = AMQP
|
|
0x01, # Major
|
|
0x00, # Minor
|
|
0x00) # Revision
|
|
|
|
[byte[]]$AMQP2 = @(
|
|
0x41, 0x4D, 0X51, 0X50, # AMQP
|
|
0x02, # Protcol = TCP
|
|
0x01, # Major
|
|
0x00, # Minor
|
|
0x00) # Revision
|
|
|
|
[byte[]]$AMQP3 = @(
|
|
0x41, 0x4D, 0X51, 0X50, # AMQP
|
|
0x03, # Protocol = SASL
|
|
0x01, # Major
|
|
0x00, # Minor
|
|
0x00) # Revision
|
|
|
|
[byte[]]$EmptyAMQPHeader = @(0x00, 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00)
|
|
|
|
Try
|
|
{
|
|
|
|
# Define some needed variables
|
|
$NameSpace = $bootStrap.NameSpace
|
|
$url = "$nameSpace.servicebus.windows.net/`$servicebus/websocket"
|
|
$connectionId = (New-Guid).ToString()
|
|
$relayLinkGuid = (New-Guid).ToString()
|
|
$trackingId = (New-Guid).ToString()
|
|
|
|
if($status)
|
|
{
|
|
$Status.status = "Connecting to $url"
|
|
}
|
|
else
|
|
{
|
|
Write-Verbose "Connecting to $url"
|
|
}
|
|
#$connector.Status = "Connecting to $url"
|
|
|
|
# Create the socket
|
|
$socket = New-Object System.Net.WebSockets.ClientWebSocket
|
|
|
|
# Add wsrelayedamqp as sub protocol
|
|
$socket.Options.AddSubProtocol("wsrelayedamqp")
|
|
$socket.Options.ClientCertificates.Add($cert) | out-null
|
|
|
|
# Create the token and open the connection
|
|
$token = New-Object System.Threading.CancellationToken
|
|
|
|
$connection = $socket.ConnectAsync("wss://$url", $token)
|
|
While (!$connection.IsCompleted) { Start-Sleep -Milliseconds 5 }
|
|
|
|
if($connection.IsFaulted -eq "True")
|
|
{
|
|
Write-Error $connection.Exception
|
|
return
|
|
}
|
|
|
|
#
|
|
# Start the Agent
|
|
#
|
|
|
|
# Send SASL version header
|
|
SendToSocket -Socket $socket -Token $token -Bytes ($AMQP3)
|
|
|
|
# DEBUG
|
|
$relayOpened=$false
|
|
|
|
# Start the loop
|
|
while($socket.state -eq "Open")
|
|
{
|
|
$outMessage = $null
|
|
|
|
$response = ReadFromSocket -Socket $socket -Token $token -KeepAlive
|
|
$inMessage = Parse-BusMessage $response
|
|
|
|
$close = $false
|
|
|
|
switch($inMessage.Type)
|
|
{
|
|
"Protocol SASL" {} # Do nothing
|
|
"SASL Mechanisms"
|
|
{
|
|
# SASL init
|
|
$outMessage = New-SASLInit -Mechanics EXTERNAL
|
|
}
|
|
"SASL Outcome"
|
|
{
|
|
# Change protocol to AMQP
|
|
$outMessage = $AMQP0
|
|
}
|
|
"Protocol AMQP"
|
|
{
|
|
# AMQP Open
|
|
$outMessage = New-AMQPOpen -ContainerId "RelayConnection_$connectionId" -HostName "$nameSpace-relay.servicebus.windows.net"
|
|
}
|
|
"AQMP Open"
|
|
{
|
|
# AMQP Begin
|
|
$outMessage = New-AMQPBegin
|
|
}
|
|
"AQMP Begin"
|
|
{
|
|
# AMQP Attach handle 0 and 1
|
|
SendToSocket -Socket $socket -Token $token -Bytes (New-AMQPAttach -Handle 0 -RelayLinkGuid $relayLinkGuid -Direction out -BootStrap $bootStrap -TrackingID $trackingId)
|
|
SendToSocket -Socket $socket -Token $token -Bytes (New-AMQPAttach -Handle 1 -RelayLinkGuid $relayLinkGuid -Direction in -BootStrap $bootStrap -TrackingID $trackingId)
|
|
|
|
$outMessage = New-AMQPFlow
|
|
}
|
|
"AQMP Attach"
|
|
{
|
|
# Nothing to do
|
|
}
|
|
"AQMP Flow"
|
|
{
|
|
# Send an empty AMQP Header
|
|
$outMessage = $EmptyAMQPHeader
|
|
if($status)
|
|
{
|
|
$Status.status += "`nWaiting for auth requests.."
|
|
}
|
|
else
|
|
{
|
|
Write-Verbose "Waiting for auth requests.."
|
|
}
|
|
}
|
|
"AQMP Detach"
|
|
{
|
|
# Send AMQP Detach
|
|
$outMessage = New-AMQPDetach -Handle ($inMessage.Handle)
|
|
Write-Verbose ($inMessage.Error)
|
|
}
|
|
"AQMP End"
|
|
{
|
|
# Send AMQP End
|
|
$outMessage = New-AMQPEnd
|
|
}
|
|
"AQMP Close"
|
|
{
|
|
# Send AMQP Close
|
|
$outMessage = New-AMQPClose
|
|
|
|
# Close the socket after sending the last message
|
|
$close = $True
|
|
|
|
# Set the status
|
|
if($status)
|
|
{
|
|
$Status.status += "`nClosed."
|
|
}
|
|
else
|
|
{
|
|
Write-Verbose "Closed."
|
|
}
|
|
}
|
|
"OnewaySend"
|
|
{
|
|
# Send the disposition message
|
|
SendToSocket -Socket $socket -Token $token -Bytes (New-AMQPDisposition)
|
|
|
|
# Time to create the relay!
|
|
if($status)
|
|
{
|
|
$Status.status += "`nOpening relay to $($inMessage.RelayAddress)"
|
|
}
|
|
else
|
|
{
|
|
Write-Verbose "Opening relay to $($inMessage.RelayAddress)"
|
|
}
|
|
|
|
if(!$relayOpened)
|
|
{
|
|
$relayOpened = $true
|
|
Connect-ToAuthRelay -Hostname $inMessage.RelayAddress -Id $inMessage.RelayId -Certificate $cert
|
|
}
|
|
}
|
|
}
|
|
|
|
if($outMessage -ne $null)
|
|
{
|
|
SendToSocket -Socket $socket -Token $token -Bytes $outMessage
|
|
|
|
}
|
|
|
|
if($close)
|
|
{
|
|
$socket.Abort()
|
|
}
|
|
|
|
}
|
|
|
|
|
|
}
|
|
catch
|
|
{
|
|
$Exception = $error[0]
|
|
Write-Host $Exception -ForegroundColor Red
|
|
}
|
|
Finally{
|
|
|
|
If ($socket) {
|
|
Write-Verbose "Closing websocket"
|
|
$socket.Dispose()
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
# Creates a SAS token
|
|
function Get-SASToken
|
|
{
|
|
|
|
[cmdletbinding()]
|
|
Param(
|
|
[Parameter(Mandatory=$True)]
|
|
[String]$Url,
|
|
[Parameter(Mandatory=$True)]
|
|
[String]$Key,
|
|
[Parameter(Mandatory=$True)]
|
|
[String]$KeyName,
|
|
[Parameter(Mandatory=$False)]
|
|
[DateTime]$Expires=(Get-Date).AddDays(1)
|
|
)
|
|
Process
|
|
{
|
|
# Create the HMAC object
|
|
$keyBytes=[Text.Encoding]::UTF8.GetBytes($Key)
|
|
$hmac = [System.Security.Cryptography.HMACSHA256]::new($keyBytes)
|
|
|
|
# Convert to UNIX time
|
|
$exp=([System.DateTimeOffset]$Expires.ToUniversalTime()).ToUnixTimeSeconds()
|
|
|
|
# Form the string to sign (urlencoded uri + \n + expires)
|
|
$namespace = $url.split("/")[2]
|
|
$urlToSign = [System.Web.HttpUtility]::UrlEncode($url) + "`n" + [string]$exp
|
|
$byteUrl=[Text.Encoding]::UTF8.GetBytes($urlToSign)
|
|
|
|
# Calculate the signature
|
|
$byteHash = $hmac.ComputeHash($byteUrl)
|
|
$signature = [System.Convert]::ToBase64String($byteHash)
|
|
|
|
# Form the token
|
|
$SASToken = "SharedAccessSignature sr=" + [System.Web.HttpUtility]::UrlEncode($Url) + "&sig=" + [System.Web.HttpUtility]::UrlEncode($signature) + "&se=" + $exp + "&skn=" + $KeyName
|
|
|
|
return $SASToken
|
|
}
|
|
}
|
|
|
|
function Connect-ToAuthRelay
|
|
{
|
|
[cmdletbinding()]
|
|
Param(
|
|
[Parameter(Mandatory=$True)]
|
|
[String]$Hostname,
|
|
[Parameter(Mandatory=$True)]
|
|
[String]$Id,
|
|
[Parameter(Mandatory=$True)]
|
|
[System.Security.Cryptography.X509Certificates.X509Certificate2]$Certificate
|
|
|
|
)
|
|
Process
|
|
{
|
|
|
|
Try
|
|
{
|
|
$url = "$Hostname/`$servicebus/websocket"
|
|
|
|
|
|
|
|
# Create the socket
|
|
$socket = New-Object System.Net.WebSockets.ClientWebSocket
|
|
|
|
# Add wsrelayedamqp as sub protocol
|
|
$socket.Options.AddSubProtocol("wsrelayedconnection")
|
|
$socket.Options.ClientCertificates.Add($Certificate) | out-null
|
|
|
|
# Create the token and open the connection
|
|
$token = New-Object System.Threading.CancellationToken
|
|
|
|
$connection = $socket.ConnectAsync("wss://$url", $token)
|
|
While (!$connection.IsCompleted) { Start-Sleep -Milliseconds 5 }
|
|
|
|
if($connection.IsFaulted -eq "True")
|
|
{
|
|
Write-Error $connection.Exception
|
|
return
|
|
}
|
|
|
|
# Send the two initial messages
|
|
SendToSocket -Socket $socket -Token $token -Bytes (New-RelayConnect)
|
|
|
|
SendToSocket -Socket $socket -Token $token -Bytes (New-RelayAccept -id $id)
|
|
|
|
# Start the conversation loop
|
|
|
|
if($status)
|
|
{
|
|
#$Status.status += "`nSocket: $($socket.state)"
|
|
}
|
|
|
|
# Define variables
|
|
$SomeId = $null
|
|
$SequenceId = $null
|
|
$ConnectionId = New-Guid
|
|
$RelayUrl = $null
|
|
$ProxyUrl = $null
|
|
$ProxyId = $null
|
|
$SomeId2 = $null
|
|
$ConId = $null
|
|
|
|
while($socket.state -eq "Open")
|
|
{
|
|
Remove-Variable outMessage
|
|
$outMessage = $null
|
|
|
|
$response = ReadFromSocket -Socket $socket -Token $token -TimeOut
|
|
|
|
if($response -eq $null)
|
|
{
|
|
return
|
|
}
|
|
|
|
$inMessage = Parse-RelayMessage $response
|
|
|
|
if($status)
|
|
{
|
|
# $Status.status += "`n$hostname InMessage: $($inMessage.Type) $($inMessage.Size). Response: $($response.length)"
|
|
}
|
|
|
|
$close = $false
|
|
|
|
|
|
|
|
switch($inMessage.Type)
|
|
{
|
|
"Relay AcceptReply" {} # Do nothing
|
|
"Relay ConnectReply" {} # Do nothing
|
|
"Relay Name"
|
|
{
|
|
# Reply
|
|
SendToSocket -Socket $socket -Token $token -Byte (New-RelayNameReply)
|
|
}
|
|
"Relay Ids"
|
|
{
|
|
if($status)
|
|
{
|
|
$Status.status += "`nExtracting variables"
|
|
}
|
|
# Extract variables
|
|
$SomeId = $inMessage.SomeId
|
|
$SequenceId = $inMessage.SequenceId
|
|
$RelayUrl = $inMessage.Relay
|
|
|
|
if($status)
|
|
{
|
|
$Status.status += "`nSending outmessage. SomeId: $someId ConnectionId $ConnectionId SequenceId: $SequenceId Relay $RelayUrl"
|
|
}
|
|
# Reply
|
|
$outMessage = New-RelayIdsReply -SomeId $SomeId -ConnectionId $ConnectionId -Relay $RelayUrl
|
|
}
|
|
"Relay ProxyConnect"
|
|
{
|
|
# Extract variables
|
|
$ProxyUrl = $inMessage.ProxyUrl
|
|
$ProxyId = $inMessage.ProxyId
|
|
$SomeId2 = $inMessage.SomeId2
|
|
$ConId = $inMessage.ConId
|
|
$ConnectionId = $inMessage.ConnectionId
|
|
|
|
if($status)
|
|
{
|
|
$Status.status += "`nProxy. SomeId2: $someId2 SequenceId: $SequenceId ConnectionId: $ConnectionId "
|
|
}
|
|
|
|
# Reply
|
|
$outMessage = New-RelayProxyConnectReply -SequenceId $SequenceId -SomeId2 $SomeId2 -ConnectionId $ConnectionId
|
|
|
|
# Send NetRemote
|
|
SendToSocket -Socket $socket -Token $token -Bytes New-RelayNetRemote
|
|
}
|
|
"Relay NetRemoteReply"
|
|
{
|
|
# Try to connect to the proxy!
|
|
|
|
# Get the ids..
|
|
$SubscriptionId=([System.Security.Cryptography.X509Certificates.X509Certificate2]$Certificate).GetNameInfo([System.Security.Cryptography.X509Certificates.X509NameType]::SimpleName,$false)
|
|
$ConnectorId=([guid]([System.Security.Cryptography.X509Certificates.X509Certificate2]$Certificate).Extensions["1.3.6.1.4.1.311.82.1"].RawData).ToString()
|
|
|
|
$url="https://$proxyUrl/subscriber/websocketconnect?requestId=$((New-Guid).ToString())"
|
|
|
|
|
|
|
|
|
|
# Create the socket
|
|
$socket2 = New-Object System.Net.WebSockets.ClientWebSocket
|
|
|
|
$socket2.options.SetRequestHeader("x-cwap-dnscachelookup-result" , "NotUsed")
|
|
$socket2.options.SetRequestHeader("x-cwap-connector-usesdefaultproxy" , "InUse")
|
|
$socket2.options.SetRequestHeader("x-cwap-connector-version" , "1.5.1542.0")
|
|
$socket2.options.SetRequestHeader("x-cwap-datamodel-version" , "1.5.1542.0")
|
|
$socket2.options.SetRequestHeader("x-cwap-connector-sp-connections" , "0")
|
|
$socket2.options.SetRequestHeader("x-cwap-transid" , $id)
|
|
|
|
$socket2.options.ClientCertificates.Add($cert)
|
|
|
|
# Create the token and open the connection
|
|
$token2 = New-Object System.Threading.CancellationToken
|
|
|
|
$connection2 = $socket2.ConnectAsync("wss://$($url.Substring(8))", $token2)
|
|
While (!$connection2.IsCompleted) { Start-Sleep -Milliseconds 5 }
|
|
|
|
if($connection2.IsFaulted -eq "True")
|
|
{
|
|
Write-Error $connection2.Exception
|
|
return
|
|
}
|
|
Write-Host "Connected to $Url" -ForegroundColor Yellow
|
|
|
|
# Send the message
|
|
$message = [text.encoding]::UTF8.GetBytes( "{`"ConnectionId`":`"$connectionId`",`"MessageType`":0}" )
|
|
SendToSocket -Socket $socket2 -Token $token -Bytes ($message)
|
|
|
|
# Loop
|
|
while($true)
|
|
{
|
|
# Get the authentication message
|
|
$response = ReadFromSocket -Socket $socket2 -Token $token2 -ArraySize 2048
|
|
# Debug -Step ($step++) -NameSpace $Hostname -Bytes $response -Direction in
|
|
|
|
$authRequest = [text.encoding]::UTF8.GetString($response)
|
|
Write-Verbose $authRequest
|
|
$credentials = Decode-PTACredential -AuthRequest $authRequest -Certificate $cert
|
|
|
|
$credentials
|
|
|
|
|
|
|
|
Write-Verbose "Trying to send authentication response"
|
|
$username="danj@highlandwhiskey.myo365.site"
|
|
$userClaim="[{`"ClaimType`":`"http:\/\/schemas.xmlsoap.org\/ws\/2005\/05\/identity\/claims\/authentication`",`"Resource`":true,`"Right`":`"http:\/\/schemas.xmlsoap.org\/ws\/2005\/05\/identity\/right\/identity`"},{`"ClaimType`":`"http:\/\/schemas.xmlsoap.org\/ws\/2005\/05\/identity\/claims\/name`",`"Resource`":`"$username`",`"Right`":`"http:\/\/schemas.xmlsoap.org\/ws\/2005\/05\/identity\/right\/identity`"}]"
|
|
$backEndResponse = [convert]::ToBase64String([text.encoding]::UTF8.GetBytes($userClaim))
|
|
|
|
$headers = [ordered]@{
|
|
"x-cwap-dnscachelookup-result"="NotUsed"
|
|
"x-cwap-connector-usesdefaultproxy"="InUse"
|
|
"x-cwap-connector-version"="1.5.1542.0"
|
|
"x-cwap-datamodel-version"="1.5.1542.0"
|
|
"x-cwap-connector-sp-connections"="1"
|
|
"x-cwap-transid" = $id
|
|
"x-cwap-sessionid"="00000000-0000-0000-0000-000000000000"
|
|
"x-cwap-certificate-authentication"="notProcessed"
|
|
"x-cwap-headers-size"="0"
|
|
"x-cwap-connector-be-latency-ms"="27"
|
|
"x-cwap-payload-total-attempts"="0"
|
|
"x-cwap-connector-loadfactor"="0"
|
|
"x-cwap-response-total-attempts"="1"
|
|
"x-cwap-connector-all-latency-ms"="70"
|
|
"x-cwap-backend-response" = $backEndResponse
|
|
"User-Agent"=""
|
|
}
|
|
|
|
$url="https://$proxyUrl/subscriber/connection?requestId=$((New-Guid).ToString())"
|
|
|
|
# The cert must be "linked" to this web page by IE + it needs to be installed in the personal store.
|
|
try
|
|
{
|
|
Invoke-RestMethod -Uri $url -Method Post -Certificate $cert -Headers $headers -ContentType "" -ErrorAction SilentlyContinue
|
|
#$response = Invoke-WebRequest -UseBasicParsing -Uri $url -Method Post -Certificate $cert -Headers $headers -ContentType "" -ErrorAction SilentlyContinue
|
|
}
|
|
catch
|
|
{
|
|
Write-Error $_.Exception.Message
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if($outMessage -ne $null)
|
|
{
|
|
if($status)
|
|
{
|
|
#$Status.status += "`nSendToSocket. $($outMessage.length). $($outMessage.GetType())"
|
|
}
|
|
SendToSocket -Socket $socket -Token $token -Bytes ([byte[]]$outMessage)
|
|
|
|
}
|
|
|
|
if($close)
|
|
{
|
|
$socket.Abort()
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
catch
|
|
{
|
|
$Exception = $error[0]
|
|
Write-Host $_
|
|
Write-Host $Exception -ForegroundColor Red
|
|
|
|
if($status)
|
|
{
|
|
$Status.status += "`n$($exception.toString())"
|
|
}
|
|
}
|
|
Finally{
|
|
|
|
If ($socket) {
|
|
Write-Verbose "Closing websocket $Namespace"
|
|
$socket.Dispose()
|
|
}
|
|
|
|
|
|
}
|
|
|
|
}
|
|
} |