-
Notifications
You must be signed in to change notification settings - Fork 1
/
LoopbackRedirection.ps1
125 lines (114 loc) · 3.88 KB
/
LoopbackRedirection.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
function GetRootUrl {
[CmdletBinding()]
param(
[Parameter(Position=0,ValueFromPipeline=$true)]
[uri]
$Url
)
process {
$Url | % {
$local:t = [UriBuilder]::new($_)
$local:t.Path = "/"
$local:t.Query = $null
$local:t.Uri
}
}
}
function SetUrlPort {
[CmdletBinding()]
param(
[Parameter(Position=0,ValueFromPipeline=$true)]
[uri]
$Url,
[Parameter(Position=1)]
[int]
$Port
)
process {
$Url | % {
$local:t = [UriBuilder]::new($_)
$local:t.Port = $Port
$local:t.Uri
}
}
}
function StartLoopbackRedirectionRequest {
[CmdletBinding()]
param(
[parameter(Mandatory=$true,Position=0)]
[uri]
$Authority,
[parameter(Mandatory=$true,Position=1)]
[PSTypeName("OAuth2.ClientConfig")]
$Client,
[parameter()]
[string]
$Browser = "default",
[parameter()]
[switch]
$Private,
[parameter()]
[switch]
$RandomPort = $true,
[parameter()]
[switch]
$AnyHost = $false,
[Parameter()]
[System.Collections.IDictionary]
$QueryString
)
begin {
if([string]::IsNullOrEmpty($Client.RedirectUri)) {
throw "redirect_uri is not defined"
}
$local:metadata = Get-Metadata -Authority $Authority -ErrorAction Stop
$local:listener = Start-HttpListener -Prefix (GetRootUrl $Client.RedirectUri) -RandomPort:$RandomPort -AnyHost:$AnyHost
$local:redirect_uri = SetUrlPort -Url $Client.RedirectUri -Port $local:listener.Prefix.Port
$local:id = [Guid]::NewGuid()
$local:html = @"
<body onload="window.close()">
<p>The operation was completed.</p>
<p><input type="button" onclick="window.close()" value="Close"></input></p>
</body>
"@;
}
process {
$local:query = $QueryString |
Add-QueryString "redirect_uri" $local:redirect_uri
if([string]::IsNullOrWhiteSpace($Client.Credential.Password)) {
$local:verifier = $null
$local:challenge = New-CodeChallenge ([ref]$verifier)
$local:query = $QueryString |
Add-QueryString "code_challenge" $local:challenge |
Add-QueryString "code_challenge_method" "S256"
} else {
$local:verifier = $null
}
$local:authorizationRequest = [UriBuilder]::new($local:metadata.authorization_endpoint)
$local:authorizationRequest.Query = (ConvertTo-QueryString $local:query)
Write-Verbose "StartLoopbackRedirectionRequest GET $local:authorizationRequest"
Start-Browser -Uri "$($local:listener.Prefix)$id" -Name $Browser -Private:$Private
$local:code = $null
$local:listener | Read-HttpRequest | % {
Write-Verbose "Read-HttpRequest $($_.Uri)"
if($_.Url.LocalPath -eq "/$id") {
$_ | Write-HttpResponse -Location $local:authorizationRequest.Uri
} elseif($_.Url.LocalPath -eq $redirect_uri.LocalPath) {
$local:code = $_.QueryString.Get("code")
$_ | Write-HttpResponse -Body $local:html -Stop
}
}
if($local:code) {
[PSCustomObject]@{
"PSTypeName" = "OAuth2.Code"
"Credential" = [pscredential]::new("code", (ConvertTo-SecureString -AsPlainText -Force -String $local:code)).GetNetworkCredential()
"RedirectUri" = $local:redirect_uri
"Verifier" = $local:verifier
}
}
}
end {
$local:listener | Stop-HttpListener
}
}
Export-ModuleMember -Function "*"