mirror of
https://github.com/Icinga/icinga-powershell-framework.git
synced 2025-12-21 15:19:58 -05:00
296 lines
No EOL
9.1 KiB
PowerShell
296 lines
No EOL
9.1 KiB
PowerShell
$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; |