lib/client/Start-IcingaRESTClientCommunication.psm1

function Start-IcingaRESTClientCommunication()
{
    param(
        [Hashtable]$Connection = @{},
        [bool]$RequireAuth     = $FALSE,
        $IcingaGlobals         = $null
    );

    # If we couldnt establish a proper SSL stream, close the connection
    # immediately without opening a client connection thread
    if ($null -eq $Connection.Stream) {
        Add-IcingaRESTClientBlacklistCount `
            -Client $Connection.Client `
            -ClientList $IcingaGlobals.BackgroundDaemon.IcingaPowerShellRestApi.ClientBlacklist;
        Write-IcingaEventMessage -EventId 1501 -Namespace 'Framework' -Objects $Connection.Client.Client;
        Close-IcingaTCPConnection -Client $Connection.Client;
        $Connection = $null;
        return;
    }

    # Our ScriptBlock for the code being executed inside the thread
    [ScriptBlock]$IcingaRestClientScript = {
        # Allow us to parse the framework global data to this thread
        param($IcingaGlobals, $Connection, $RequireAuth);

        # Import the framework library components and initialise it
        # as daemon
        Use-Icinga -Daemon;

        # Map our Icinga globals to a shorter variable
        $RestDaemon = $IcingaGlobals.BackgroundDaemon.IcingaPowerShellRestApi;

        # Read the received message from the stream by using our smart functions
        [string]$RestMessage = Read-IcingaTCPStream -Client $Connection.Client -Stream $Connection.Stream;
        # Now properly translate the entire rest message to a parseable hashtable
        $RESTRequest         = Read-IcingaRestMessage -RestMessage $RestMessage -Connection $Connection;

        if ($null -ne $RESTRequest) {

            # Check if we require to authenticate the user
            if ($RequireAuth) {
                # If no authentication header is provided we should show the prompt
                if ([string]::IsNullOrEmpty($RESTRequest.Header.Authorization)) {
                    # In case we do not send an authentication header increase the blacklist counter
                    # to ensure we are not spammed and "attacked" by a client with useless requests
                    Add-IcingaRESTClientBlacklistCount `
                        -Client $Connection.Client `
                        -ClientList $IcingaGlobals.BackgroundDaemon.IcingaPowerShellRestApi.ClientBlacklist;
                    # Send the authentication prompt
                    Send-IcingaWebAuthMessage -Connection $Connection;
                    # Close the connection
                    Close-IcingaTCPConnection -Client $Connection.Client;
                    return;
                }

                $Credentials        = Convert-Base64ToCredentials -AuthString $RESTRequest.Header.Authorization;
                [bool]$LoginSuccess = Test-IcingaRESTCredentials -UserName $Credentials.user -Password $Credentials.password -Domain $Credentials.domain;
                $Credentials        = $null;
    
                # Handle login failures
                if ($LoginSuccess -eq $FALSE) {
                    # Failed attempts should increase the blacklist counter
                    Add-IcingaRESTClientBlacklistCount `
                        -Client $Connection.Client `
                        -ClientList $IcingaGlobals.BackgroundDaemon.IcingaPowerShellRestApi.ClientBlacklist;
                    # Re-send the authentication prompt
                    Send-IcingaWebAuthMessage -Connection $Connection;
                    # Close the connection
                    Close-IcingaTCPConnection -Client $Connection.Client;
                    return;
                }
            }

            # We should remove clients from the blacklist who are sending valid requests
            Remove-IcingaRESTClientBlacklist -Client $Connection.Client -ClientList $RestDaemon.ClientBlacklist;
            switch (Get-IcingaRESTPathElement -Request $RESTRequest -Index 0) {
                'v1' {
                    Invoke-IcingaRESTAPIv1Calls -Request $RESTRequest -Connection $Connection -IcingaGlobals $IcingaGlobals;
                    break;
                };
                default {
                    # Todo: Add client response for invalid request
                    Write-IcingaDebugMessage -Message ('Invalid API call - no version specified' + ($RESTRequest.RequestPath | Out-String));
                    Send-IcingaTCPClientMessage -Message (
                        New-IcingaTCPClientRESTMessage `
                            -HTTPResponse ($IcingaHTTPEnums.HTTPResponseType.'Not Found') `
                            -ContentBody 'Invalid API call received. No version specified.'
                    ) -Stream $Connection.Stream;
                };
            }
        }

        # Finally close the clients connection as we are done here and
        # ensure this thread will close by simply leaving the ScriptBlock
        Close-IcingaTCPConnection -Client $Connection.Client;
    }

    # Now create a new thread for our ScriptBlock, assign a name and
    # parse all required arguments to it. Last but not least start it
    # directly
    New-IcingaThreadInstance `
        -Name ([string]::Format("Icinga_PowerShell_Module_REST_Client_{0}", (Get-IcingaTCPClientRemoteEndpoint -Client $Connection.Client))) `
        -ThreadPool $IcingaGlobals.IcingaThreadPool.BackgroundPool `
        -ScriptBlock $IcingaRestClientScript `
        -Arguments @( $IcingaGlobals, $Connection, $RequireAuth ) `
        -Start;
}