Providers/Authentik/Private/Import-AuthentikCredential.ps1

function Import-AuthentikCredential {
    <#
    .SYNOPSIS
        Reads the service account credential record and recovers its token

    .DESCRIPTION
        The inverse of Export-AuthentikCredential. The record says where the token is, and
        this reads it from there: the SecretStore vault it names, or the DPAPI-protected value
        in the record itself. A record with no protection at all - written on a platform that
        could not encrypt - is read with a warning, so nobody mistakes it for a safe file.

        A byte order mark is stripped before parsing, because a record edited by hand in an
        editor that adds one would otherwise fail as malformed JSON.

    .PARAMETER Path
        The record to read.

    .PARAMETER VaultPassword
        The vault's password, when the token is in a vault whose password is not a default.

    .OUTPUTS
        PSCustomObject with BaseUrl, Username, UserPk, Token, Protection, VaultName, SecretName,
        CreatedUtc and Path.

    .EXAMPLE
        PS> $credential = Import-AuthentikCredential -Path $path

        DESCRIPTION: Reads the record and recovers the token
        OUTPUT: The credential with its plaintext token
        USE CASE: Connect-AuthentikEnvironment -ServiceAccount

    .NOTES
        Author: Jeffrey Stuhr
        Blog: https://www.techbyjeff.net
        LinkedIn: https://www.linkedin.com/in/jeffrey-stuhr-034214aa/
    #>


    [CmdletBinding()]
    [OutputType([PSCustomObject])]
    param(
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string]$Path,

        [Parameter()]
        [System.Security.SecureString]$VaultPassword
    )

    if (-not (Test-Path -LiteralPath $Path)) {
        throw "No service account credential record at $Path. Run New-TestServiceApp after connecting with an API token."
    }

    $bytes = [System.IO.File]::ReadAllBytes($Path)
    $text = [System.Text.Encoding]::UTF8.GetString($bytes).TrimStart([char]0xFEFF)
    $record = $text | ConvertFrom-Json

    foreach ($required in 'baseUrl', 'username', 'userPk') {
        if (-not $record.PSObject.Properties[$required] -or [string]::IsNullOrWhiteSpace([string]$record.$required)) {
            throw "The credential record at $Path has no '$required'. Re-run New-TestServiceApp -Force."
        }
    }

    $protection = if ($record.PSObject.Properties['protection'] -and $record.protection) { [string]$record.protection } else { 'None' }

    $token = switch ($protection) {
        'SecretStore' {
            Get-TestVaultSecret -VaultName $record.vaultName -SecretName $record.secretName -VaultPassword $VaultPassword
        }
        'DPAPI' {
            Unprotect-TestSecret -Method DPAPI -Value $record.tokenProtected
        }
        default {
            Write-Warning "The token in $Path is stored unprotected. Re-run New-TestServiceApp -Force -UseSecretStore to encrypt it."
            [string]$record.tokenProtected
        }
    }

    if ([string]::IsNullOrWhiteSpace($token)) {
        throw "The credential record at $Path yielded no token. Re-run New-TestServiceApp -Force."
    }

    return [PSCustomObject]@{
        BaseUrl    = [string]$record.baseUrl
        Username   = [string]$record.username
        UserPk     = [int]$record.userPk
        Token      = $token
        Protection = $protection
        VaultName  = $(if ($record.PSObject.Properties['vaultName']) { $record.vaultName } else { $null })
        SecretName = $(if ($record.PSObject.Properties['secretName']) { $record.secretName } else { $null })
        CreatedUtc = $(if ($record.PSObject.Properties['createdUtc']) { $record.createdUtc } else { $null })
        Path       = $Path
    }
}