Skip to content

Commit 13f329e

Browse files
authored
[powershell-experimental] : http signature authentication implementation (#6176)
* ValidatePattern having double quote(") throws exception on running Build.ps1 * fix tab with space * [powershell-experimental] : http signature auth * fix the tab issue Co-authored-by: Ghufran Zahidi <[email protected]>
1 parent 5f2270a commit 13f329e

File tree

4 files changed

+559
-1
lines changed

4 files changed

+559
-1
lines changed

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PowerShellExperimentalClientCodegen.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,9 @@ public void processOpts() {
615615
supportingFiles.add(new SupportingFile("api_client.mustache", infrastructureFolder + "Private", apiNamePrefix + "ApiClient.ps1"));
616616
supportingFiles.add(new SupportingFile("Get-CommonParameters.mustache", infrastructureFolder + File.separator + "Private" + File.separator, "Get-CommonParameters.ps1"));
617617
supportingFiles.add(new SupportingFile("Out-DebugParameter.mustache", infrastructureFolder + File.separator + "Private" + File.separator, "Out-DebugParameter.ps1"));
618+
supportingFiles.add(new SupportingFile("http_signature_auth.mustache", infrastructureFolder + "Private", apiNamePrefix + "HttpSignatureAuth.ps1"));
619+
supportingFiles.add(new SupportingFile("rsa_provider.mustache", infrastructureFolder + "Private", apiNamePrefix + "RSAEncryptionProvider.cs"));
620+
618621

619622
// en-US
620623
supportingFiles.add(new SupportingFile("about_Org.OpenAPITools.help.txt.mustache", infrastructureFolder + File.separator + "en-US" + File.separator + "about_" + packageName + ".help.txt"));
@@ -626,7 +629,7 @@ public void processOpts() {
626629
@SuppressWarnings("static-method")
627630
@Override
628631
public String escapeText(String input) {
629-
632+
630633
if (input == null) {
631634
return input;
632635
}
@@ -643,6 +646,7 @@ public String escapeText(String input) {
643646
.replaceAll("[\\t\\n\\r]", " ")
644647
.replace("\\", "\\\\")
645648
.replace("\"", "\"\""));
649+
646650
}
647651

648652
@Override

modules/openapi-generator/src/main/resources/powershell-experimental/api_client.mustache

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,21 @@ function Invoke-{{{apiNamePrefix}}}ApiClient {
8989
$RequestBody = $Body
9090
}
9191

92+
# http signature authentication
93+
if ($null -ne $Configuration['ApiKey'] -and $Configuration['ApiKey'].Count -gt 0) {
94+
$httpSignHeaderArgument = @{
95+
Method = $Method
96+
UriBuilder = $UriBuilder
97+
Body = $Body
98+
}
99+
$signedHeader = Get-{{{apiNamePrefix}}}HttpSignedHeader @httpSignHeaderArgument
100+
if($null -ne $signedHeader -and $signedHeader.Count -gt 0){
101+
foreach($item in $signedHeader.GetEnumerator()){
102+
$HeaderParameters[$item.Name] = $item.Value
103+
}
104+
}
105+
}
106+
92107
if ($SkipCertificateCheck -eq $true) {
93108
$Response = Invoke-WebRequest -Uri $UriBuilder.Uri `
94109
-Method $Method `
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
{{>partial_header}}
2+
<#
3+
.SYNOPSIS
4+
Get the API key Id and API key file path.
5+
6+
.DESCRIPTION
7+
Get the API key Id and API key file path. If no api prefix is provided then it use default api key prefix 'Signature'
8+
.OUTPUTS
9+
PSCustomObject : This contains APIKeyId, APIKeyFilePath, APIKeyPrefix
10+
#>
11+
function Get-{{{apiNamePrefix}}}APIKeyInfo {
12+
$ApiKeysList = $Script:Configuration['ApiKey']
13+
$ApiKeyPrefixList = $Script:Configuration['ApiKeyPrefix']
14+
$apiPrefix = "Signature"
15+
16+
if ($null -eq $ApiKeysList -or $ApiKeysList.Count -eq 0) {
17+
throw "Unable to reterieve the api key details"
18+
}
19+
20+
if ($null -eq $ApiKeyPrefixList -or $ApiKeyPrefixList.Count -eq 0) {
21+
Write-Verbose "Unable to reterieve the api key prefix details,setting it to default ""Signature"""
22+
}
23+
24+
foreach ($item in $ApiKeysList.GetEnumerator()) {
25+
if (![string]::IsNullOrEmpty($item.Name)) {
26+
if (Test-Path -Path $item.Value) {
27+
$apiKey = $item.Value
28+
$apikeyId = $item.Name
29+
break;
30+
}
31+
else {
32+
throw "API key file path does not exist."
33+
}
34+
}
35+
}
36+
37+
if ($ApiKeyPrefixList.ContainsKey($apikeyId)) {
38+
$apiPrefix = ApiKeyPrefixList[$apikeyId]
39+
}
40+
41+
if ($apikeyId -and $apiKey -and $apiPrefix) {
42+
$result = New-Object -Type PSCustomObject -Property @{
43+
ApiKeyId = $apikeyId;
44+
ApiKeyFilePath = $apiKey
45+
ApiKeyPrefix = $apiPrefix
46+
}
47+
}
48+
else {
49+
return $null
50+
}
51+
return $result
52+
}
53+
54+
<#
55+
.SYNOPSIS
56+
Gets the headers for http signed auth.
57+
58+
.DESCRIPTION
59+
Gets the headers for the http signed auth. It use (targetpath), date, host and body digest to create authorization header.
60+
.PARAMETER Method
61+
Http method
62+
.PARAMETER UriBuilder
63+
UriBuilder for url and query parameter
64+
.PARAMETER Body
65+
Request body
66+
.OUTPUTS
67+
Hashtable
68+
#>
69+
function Get-{{{apiNamePrefix}}}HttpSignedHeader {
70+
param(
71+
[string]$Method,
72+
[System.UriBuilder]$UriBuilder,
73+
[string]$Body
74+
)
75+
76+
#Hash table to store singed headers
77+
$HttpSignedHeader = @{}
78+
$TargetHost = $UriBuilder.Host
79+
80+
#Check for Authentication type
81+
$apiKeyInfo = Get-{{{apiNamePrefix}}}APIKeyInfo
82+
if ($null -eq $apiKeyInfo) {
83+
throw "Unable to reterieve the api key info "
84+
}
85+
86+
#get the body digest
87+
$bodyHash = Get-{{{apiNamePrefix}}}StringHash -String $Body
88+
$Digest = [String]::Format("SHA-256={0}", [Convert]::ToBase64String($bodyHash))
89+
90+
#get the date in UTC
91+
$dateTime = Get-Date
92+
$currentDate = $dateTime.ToUniversalTime().ToString("r")
93+
94+
$requestTargetPath = [string]::Format("{0} {1}{2}",$Method.ToLower(),$UriBuilder.Path.ToLower(),$UriBuilder.Query)
95+
$h_requestTarget = [string]::Format("(request-target): {0}",$requestTargetPath)
96+
$h_cdate = [string]::Format("date: {0}",$currentDate)
97+
$h_digest = [string]::Format("digest: {0}",$Digest)
98+
$h_targetHost = [string]::Format("host: {0}",$TargetHost)
99+
100+
$stringToSign = [String]::Format("{0}`n{1}`n{2}`n{3}",
101+
$h_requestTarget,$h_cdate,
102+
$h_targetHost,$h_digest)
103+
104+
$hashedString = Get-{{{apiNamePrefix}}}StringHash -String $stringToSign
105+
$signedHeader = Get-{{{apiNamePrefix}}}RSASHA256SignedString -APIKeyFilePath $apiKeyInfo.ApiKeyFilePath -DataToSign $hashedString
106+
$authorizationHeader = [string]::Format("{0} keyId=""{1}"",algorithm=""rsa-sha256"",headers=""(request-target) date host digest"",signature=""{2}""",
107+
$apiKeyInfo.ApiKeyPrefix, $apiKeyInfo.ApiKeyId, $signedHeader)
108+
109+
$HttpSignedHeader["Date"] = $currentDate
110+
$HttpSignedHeader["Host"] = $TargetHost
111+
$HttpSignedHeader["Content-Type"] = "application/json"
112+
$HttpSignedHeader["Digest"] = $Digest
113+
$HttpSignedHeader["Authorization"] = $authorizationHeader
114+
return $HttpSignedHeader
115+
}
116+
117+
<#
118+
.SYNOPSIS
119+
Gets the headers for http signed auth.
120+
121+
.DESCRIPTION
122+
Gets the headers for the http signed auth. It use (targetpath), date, host and body digest to create authorization header.
123+
.PARAMETER APIKeyFilePath
124+
Specify the API key file path
125+
.PARAMETER DataToSign
126+
Specify the data to sign
127+
.OUTPUTS
128+
String
129+
#>
130+
function Get-{{{apiNamePrefix}}}RSASHA256SignedString {
131+
Param(
132+
[string]$APIKeyFilePath,
133+
[byte[]]$DataToSign
134+
)
135+
try {
136+
137+
$rsa_provider_path = Join-Path -Path $PSScriptRoot -ChildPath "{{{apiNamePrefix}}}RSAEncryptionProvider.cs"
138+
$rsa_provider_sourceCode = Get-Content -Path $rsa_provider_path -Raw
139+
Add-Type -TypeDefinition $rsa_provider_sourceCode
140+
$signed_string = [RSAEncryption.RSAEncryptionProvider]::GetRSASignb64encode($APIKeyFilePath, $DataToSign)
141+
if ($null -eq $signed_string) {
142+
throw "Unable to sign the header using the API key"
143+
}
144+
return $signed_string
145+
}
146+
catch {
147+
throw $_
148+
}
149+
}
150+
<#
151+
.Synopsis
152+
Gets the hash of string.
153+
.Description
154+
Gets the hash of string
155+
.Outputs
156+
String
157+
#>
158+
Function Get-{{{apiNamePrefix}}}StringHash([String] $String, $HashName = "SHA256") {
159+
160+
$hashAlogrithm = [System.Security.Cryptography.HashAlgorithm]::Create($HashName)
161+
$hashAlogrithm.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($String))
162+
}

0 commit comments

Comments
 (0)