icinga-powershell-framework/core/include/utils/WebHelper.ps1

296 lines
9.1 KiB
PowerShell
Raw Normal View History

2018-11-06 11:14:49 -05:00
$WebHelper = New-Object -TypeName PSObject;
$WebHelper | Add-Member -membertype ScriptMethod -name 'ParseApiMessage' -value {
param([SecureString]$message);
try {
[hashtable]$HeaderContent = @{};
if ($message -eq $null) {
return $HeaderContent;
}
[string]$HTMLMessage = $Icinga2.Utils.SecureString.ConvertFrom($message);
[string]$HTMLContent = '';
if ($HTMLMessage.Contains("`r`n`r`n")) {
[int]$EOFIndex = $HTMLMessage.IndexOf("`r`n`r`n") + 4;
$HTMLContent = $HTMLMessage.Substring(
$EOFIndex,
$HTMLMessage.Length - $EOFIndex
);
# Remove the content from our message
if ([string]::IsNullOrEmpty($HTMLContent) -eq $FALSE) {
$HTMLMessage = $HTMLMessage.Replace($HTMLContent, '');
}
}
[array]$SingleHeaders = $HTMLMessage.Split("`r`n");
$HTMLMessage = $null;
# At first read the method, the http call and the protocol
$HeaderContent.Add(
'base',
$this.ParseMethodAndUrl($SingleHeaders[0])
);
# Now add possible content to our hashtable
$HeaderContent.Add(
'content',
$HTMLContent
);
# Drop the first entry of the array, as we no longer require it
$SingleHeaders = $SingleHeaders | Select-Object -Skip 1;
# Read the headers from the array
$HeaderContent.Add(
'headers',
$this.ParseHeaders($SingleHeaders)
);
# Flush the array from the memory
$SingleHeaders = $null;
if ($HeaderContent.headers.ContainsKey('Authorization')) {
$HeaderContent.Add(
'credentials',
$this.ParseUserCredentials(
$HeaderContent.headers.Authorization
)
);
$HeaderContent.headers.Remove('Authorization');
}
return $HeaderContent;
}
catch {
$Icinga2.Log.Write(
$Icinga2.Enums.LogState.Exception,
[string]::Format(
'Failed to parse HTTP content and headers. Error {0}',
$_.Exception.Message
)
);
}
return $null;
}
$WebHelper | Add-Member -membertype ScriptMethod -name 'ParseMethodAndUrl' -value {
param([string]$message);
[array]$Content = $message.Split(' ');
[uri]$UriData = [uri][string]::Format(
'https://localhost{0}',
$Content[1]
);
return @{
method = $Content[0];
call = [System.Web.HttpUtility]::UrlDecode(
$Content[1]
);
protocol = $Content[2];
segments = $UriData.Segments;
query = [System.Web.HttpUtility]::UrlDecode(
$UriData.Query
);
}
}
$WebHelper | Add-Member -membertype ScriptMethod -name 'ParseHeaders' -value {
param([array]$message);
[hashtable]$Headers = @{};
foreach ($header in $message) {
[string]$HeaderName = '';
[string]$HeaderValue = '';
# Skip empty array values
if ([string]::IsNullOrEmpty($header) -eq $FALSE) {
if ($header.Contains(':')) {
[array]$Element = $header.Split(':');
$HeaderName = $Element[0];
if ($Element.Count -gt 1) {
for ($i = 1; $i -le ($Element.Count - 1); $i++) {
$HeaderValue = -Join(
$HeaderValue,
$Element[$i],
':'
);
}
}
# Remove the last added ':' at the end of the string
if ($HeaderValue.Length -gt 1) {
$HeaderValue = $HeaderValue.Substring(
0,
$HeaderValue.Length - 1
);
}
# In case the first letter of our value is a space, remove it
while ($HeaderValue[0] -eq ' ') {
$HeaderValue = $HeaderValue.Substring(
1,
$HeaderValue.Length - 1
);
}
if ($Headers.ContainsKey($HeaderName) -eq $FALSE) {
# We have to modify the Authorization header value a little more and also
# ensure we store it as secure string within our module
if ($HeaderName -eq 'Authorization') {
[array]$AuthArray = $HeaderValue.Split(' ');
# TODO: Shall we handle each auth type differently?
$Headers.Add(
$HeaderName,
$Icinga2.Utils.SecureString.ConvertTo($AuthArray[1])
);
$AuthArray = $null;
} else {
$Headers.Add($HeaderName, $HeaderValue);
}
}
} else {
$Headers.Add($header, $null);
}
}
}
return $Headers;
}
$WebHelper | Add-Member -membertype ScriptMethod -name 'ParseUserCredentials' -value {
param([SecureString]$Base64String);
[hashtable]$Credentials = @{};
if ($Base64String -eq $null) {
return $Credentials;
}
# Convert the Base64 Secure String back to a normal string
[string]$PlainAuth = [System.Text.Encoding]::UTF8.GetString(
[System.Convert]::FromBase64String(
$Icinga2.Utils.SecureString.ConvertFrom($Base64String)
)
);
$Base64String = $null;
# If no ':' is within the string, the credential data is not properly formated
if ($PlainAuth.Contains(':') -eq $FALSE) {
$Icinga2.Log.Write(
$Icinga2.Enums.LogState.Warning,
'Received invalid formated credentials as Base64 encoded.'
);
$PlainAuth = $null;
return $Credentials;
}
try {
# Build our User Data and Password from the string
[string]$UserData = $PlainAuth.Substring(
0,
$PlainAuth.IndexOf(':')
);
$Credentials.Add(
'password',
$Icinga2.Utils.SecureString.ConvertTo(
$PlainAuth.Substring(
$PlainAuth.IndexOf(':') + 1,
$PlainAuth.Length - $UserData.Length - 1
)
)
);
$PlainAuth = $null;
# Extract a possible domain
if ($UserData.Contains('\')) {
# Split the auth string on the '\'
[array]$AuthData = $UserData.Split('\');
# First value of the array is the Domain, second is the Username
$Credentials.Add('domain', $AuthData[0]);
$Credentials.Add(
'user',
$Icinga2.Utils.SecureString.ConvertTo(
$AuthData[1]
)
);
$AuthData = $null;
} else {
$Credentials.Add('domain', $null);
$Credentials.Add(
'user',
$Icinga2.Utils.SecureString.ConvertTo(
$UserData
)
);
}
$UserData = $null;
} catch {
$Icinga2.Log.Write(
$Icinga2.Enums.LogState.Error,
'Failed to handle authentication request. An exception occured while processing the request.'
);
}
return $Credentials;
}
$WebHelper | Add-Member -membertype ScriptMethod -name 'ParseUrlCommand' -value {
param([string]$Argument);
[hashtable]$StructuredCommand = @{};
# If no = is included, we don't need to handle anything special
if ($Argument.Contains('=') -eq $FALSE) {
$StructuredCommand.Add($Argument, $null);
return $StructuredCommand;
}
[int]$SeperatorIndex = $Argument.IndexOf('=');
[string]$Command = $Argument.Substring(
0,
$SeperatorIndex
);
$Command = $Command.Replace(' ', '').ToLower();
[array]$Values = @();
[string]$Value = $Argument.Substring(
$SeperatorIndex + 1,
$Argument.Length - $SeperatorIndex - 1
);
if ($Value.Contains(',') -eq $TRUE) {
[array]$Entries = $Value.Split(',');
foreach ($entry in $Entries) {
[string]$ParsedValue = $entry;
# Cut spaces before names of inputs
while ($ParsedValue[0] -eq ' ') {
$ParsedValue = $ParsedValue.Substring(
1,
$ParsedValue.Length - 1
);
}
# Cut spaces after names of inputs
while ($ParsedValue[$ParsedValue.Length - 1] -eq ' ') {
$ParsedValue = $ParsedValue.Substring(
0,
$ParsedValue.Length - 1
);
}
$Values += $ParsedValue.ToLower();
}
} else {
$Values += $Value.Replace(' ', '').ToLower();
}
# Filter out duplicate entries
$Values = $Values | Select-Object -Unique;
$StructuredCommand.Add($Command, $Values);
return $StructuredCommand;
}
return $WebHelper;