diff --git a/.github/workflows/keyfactor-starter-workflow.yml b/.github/workflows/keyfactor-starter-workflow.yml index 7d01cfb..8ec5771 100644 --- a/.github/workflows/keyfactor-starter-workflow.yml +++ b/.github/workflows/keyfactor-starter-workflow.yml @@ -11,18 +11,17 @@ on: jobs: call-starter-workflow: - uses: keyfactor/actions/.github/workflows/starter.yml@screenshots + uses: keyfactor/actions/.github/workflows/starter.yml@v4 with: - command_token_url: ${{ vars.DOCTOOL_COMMAND_TOKEN_URL }} - command_hostname: ${{ vars.DOCTOOL_COMMAND_HOSTNAME }} - command_base_api_path: ${{ vars.DOCTOOL_COMMAND_BASE_API_PATH }} + command_token_url: ${{ vars.COMMAND_TOKEN_URL }} # Only required for doctool generated screenshots + command_hostname: ${{ vars.COMMAND_HOSTNAME }} # Only required for doctool generated screenshots + command_base_api_path: ${{ vars.COMMAND_API_PATH }} # Only required for doctool generated screenshots secrets: - token: ${{ secrets.V2BUILDTOKEN}} - APPROVE_README_PUSH: ${{ secrets.APPROVE_README_PUSH}} - gpg_key: ${{ secrets.KF_GPG_PRIVATE_KEY }} - gpg_pass: ${{ secrets.KF_GPG_PASSPHRASE }} - scan_token: ${{ secrets.SAST_TOKEN }} - entra_username: ${{ secrets.DOCTOOL_ENTRA_USERNAME }} - entra_password: ${{ secrets.DOCTOOL_ENTRA_PASSWD }} - command_client_id: ${{ secrets.DOCTOOL_COMMAND_CLIENT_ID }} - command_client_secret: ${{ secrets.DOCTOOL_COMMAND_CLIENT_SECRET }} \ No newline at end of file + token: ${{ secrets.V2BUILDTOKEN}} # REQUIRED + gpg_key: ${{ secrets.KF_GPG_PRIVATE_KEY }} # Only required for golang builds + gpg_pass: ${{ secrets.KF_GPG_PASSPHRASE }} # Only required for golang builds + scan_token: ${{ secrets.SAST_TOKEN }} # REQUIRED + entra_username: ${{ secrets.DOCTOOL_ENTRA_USERNAME }} # Only required for doctool generated screenshots + entra_password: ${{ secrets.DOCTOOL_ENTRA_PASSWD }} # Only required for doctool generated screenshots + command_client_id: ${{ secrets.COMMAND_CLIENT_ID }} # Only required for doctool generated screenshots + command_client_secret: ${{ secrets.COMMAND_CLIENT_SECRET }} # Only required for doctool generated screenshots diff --git a/CHANGELOG.md b/CHANGELOG.md index f3c7f62..340a099 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +v1.1.2 +- Modify error message to indicate comma separated API ID/API Key in the Store Password rather than pipe delimted + v1.1.1 - Bug fix to prevent API key logging diff --git a/Imperva/BaseJob.cs b/Imperva/BaseJob.cs index 157030d..89f13df 100644 --- a/Imperva/BaseJob.cs +++ b/Imperva/BaseJob.cs @@ -18,7 +18,7 @@ internal void SetAPIProperties(string apiUrl, string accountID, string apiIDKey) { string[] properties = apiIDKey.Split(new char[] { ',' }); if (properties.Length != 2) - throw new ImpervaException("Invalid Store Password. Value must a string with 2 values, your Api ID then Api Key separated by '|'"); + throw new ImpervaException("Invalid Store Password. Value must a string with 2 values, your Api ID then Api Key separated by ','"); ApiURL = apiUrl; AccountID = accountID; diff --git a/README.md b/README.md index 023dc36..6c6a1c7 100644 --- a/README.md +++ b/README.md @@ -40,9 +40,9 @@ The Imperva Orchestrator Extension allows for the management of SSL certificates This integration is compatible with Keyfactor Universal Orchestrator version 10.1 and later. ## Support -The Imperva Universal Orchestrator extension If you have a support issue, please open a support ticket by either contacting your Keyfactor representative or via the Keyfactor Support Portal at https://support.keyfactor.com. +The Imperva Universal Orchestrator extension is supported by Keyfactor. If you require support for any issues or have feature request, please open a support ticket by either contacting your Keyfactor representative or via the Keyfactor Support Portal at https://support.keyfactor.com. -> To report a problem or suggest a new feature, use the **[Issues](../../issues)** tab. If you want to contribute actual bug fixes or proposed enhancements, use the **[Pull requests](../../pulls)** tab. +> If you want to contribute bug fixes or additional enhancements, use the **[Pull requests](../../pulls)** tab. ## Requirements & Prerequisites @@ -148,21 +148,23 @@ the Keyfactor Command Portal ![Imperva Custom Fields Tab](docsource/images/Imperva-custom-fields-store-type-dialog.png) + + + ## Installation 1. **Download the latest Imperva Universal Orchestrator extension from GitHub.** - Navigate to the [Imperva Universal Orchestrator extension GitHub version page](https://github.com/Keyfactor/imperva-orchestrator/releases/latest). Refer to the compatibility matrix below to determine whether the `net6.0` or `net8.0` asset should be downloaded. Then, click the corresponding asset to download the zip archive. + Navigate to the [Imperva Universal Orchestrator extension GitHub version page](https://github.com/Keyfactor/imperva-orchestrator/releases/latest). Refer to the compatibility matrix below to determine the asset should be downloaded. Then, click the corresponding asset to download the zip archive. | Universal Orchestrator Version | Latest .NET version installed on the Universal Orchestrator server | `rollForward` condition in `Orchestrator.runtimeconfig.json` | `imperva-orchestrator` .NET version to download | | --------- | ----------- | ----------- | ----------- | | Older than `11.0.0` | | | `net6.0` | | Between `11.0.0` and `11.5.1` (inclusive) | `net6.0` | | `net6.0` | - | Between `11.0.0` and `11.5.1` (inclusive) | `net8.0` | `Disable` | `net6.0` | - | Between `11.0.0` and `11.5.1` (inclusive) | `net8.0` | `LatestMajor` | `net8.0` | - | `11.6` _and_ newer | `net8.0` | | `net8.0` | + | Between `11.0.0` and `11.5.1` (inclusive) | `net8.0` | `Disable` | `net6.0` || Between `11.0.0` and `11.5.1` (inclusive) | `net8.0` | `LatestMajor` | `net8.0` | + | `11.6` _and_ newer | `net8.0` | | `net8.0` | Unzip the archive containing extension assemblies to a known location. diff --git a/docsource/images/Imperva-advanced-store-type-dialog.png b/docsource/images/Imperva-advanced-store-type-dialog.png index 43ad1e4..cff8f23 100644 Binary files a/docsource/images/Imperva-advanced-store-type-dialog.png and b/docsource/images/Imperva-advanced-store-type-dialog.png differ diff --git a/docsource/images/Imperva-basic-store-type-dialog.png b/docsource/images/Imperva-basic-store-type-dialog.png index cf91b7c..14cf98b 100644 Binary files a/docsource/images/Imperva-basic-store-type-dialog.png and b/docsource/images/Imperva-basic-store-type-dialog.png differ diff --git a/docsource/images/Imperva-custom-fields-store-type-dialog.png b/docsource/images/Imperva-custom-fields-store-type-dialog.png index 515d158..a980c73 100644 Binary files a/docsource/images/Imperva-custom-fields-store-type-dialog.png and b/docsource/images/Imperva-custom-fields-store-type-dialog.png differ diff --git a/scripts/store_types/bash/curl_create_store_types.sh b/scripts/store_types/bash/curl_create_store_types.sh new file mode 100755 index 0000000..60cd525 --- /dev/null +++ b/scripts/store_types/bash/curl_create_store_types.sh @@ -0,0 +1,106 @@ +#!/usr/bin/env bash + +# Creates all 1 store types via the Keyfactor Command REST API using curl. +# +# Authentication (first matching method is used): +# OAuth access token: KEYFACTOR_AUTH_ACCESS_TOKEN +# OAuth client creds: KEYFACTOR_AUTH_CLIENT_ID + KEYFACTOR_AUTH_CLIENT_SECRET +# + KEYFACTOR_AUTH_TOKEN_URL +# Basic auth (AD): KEYFACTOR_USERNAME + KEYFACTOR_PASSWORD + KEYFACTOR_DOMAIN +# +# Always required: +# KEYFACTOR_HOSTNAME Command hostname (e.g. my-command.example.com) +# +# Auto-generated by doctool generate-store-type-scripts — do not edit by hand. + +if [ -z "${KEYFACTOR_HOSTNAME}" ]; then + echo "ERROR: KEYFACTOR_HOSTNAME is required" + exit 1 +fi + +BASE_URL="https://${KEYFACTOR_HOSTNAME}/keyfactorapi" + +# --------------------------------------------------------------------------- +# Resolve auth +# --------------------------------------------------------------------------- +if [ -n "${KEYFACTOR_AUTH_ACCESS_TOKEN}" ]; then + BEARER_TOKEN="${KEYFACTOR_AUTH_ACCESS_TOKEN}" +elif [ -n "${KEYFACTOR_AUTH_CLIENT_ID}" ] && [ -n "${KEYFACTOR_AUTH_CLIENT_SECRET}" ] && [ -n "${KEYFACTOR_AUTH_TOKEN_URL}" ]; then + echo "Fetching OAuth token..." + BEARER_TOKEN=$(curl -s -X POST "${KEYFACTOR_AUTH_TOKEN_URL}" \ + -H "Content-Type: application/x-www-form-urlencoded" \ + --data-urlencode "grant_type=client_credentials" \ + --data-urlencode "client_id=${KEYFACTOR_AUTH_CLIENT_ID}" \ + --data-urlencode "client_secret=${KEYFACTOR_AUTH_CLIENT_SECRET}" | jq -r '.access_token') + if [ -z "${BEARER_TOKEN}" ] || [ "${BEARER_TOKEN}" = "null" ]; then + echo "ERROR: Failed to fetch OAuth token from ${KEYFACTOR_AUTH_TOKEN_URL}" + exit 1 + fi +elif [ -n "${KEYFACTOR_USERNAME}" ] && [ -n "${KEYFACTOR_PASSWORD}" ] && [ -n "${KEYFACTOR_DOMAIN}" ]; then + BEARER_TOKEN="" +else + echo "ERROR: Authentication required. Set one of:" + echo " KEYFACTOR_AUTH_ACCESS_TOKEN" + echo " KEYFACTOR_AUTH_CLIENT_ID + KEYFACTOR_AUTH_CLIENT_SECRET + KEYFACTOR_AUTH_TOKEN_URL" + echo " KEYFACTOR_USERNAME + KEYFACTOR_PASSWORD + KEYFACTOR_DOMAIN" + exit 1 +fi + +if [ -n "${BEARER_TOKEN}" ]; then + CURL_AUTH=("-H" "Authorization: Bearer ${BEARER_TOKEN}") +else + CURL_AUTH=("-u" "${KEYFACTOR_USERNAME}@${KEYFACTOR_DOMAIN}:${KEYFACTOR_PASSWORD}") +fi + +create_store_type() { + local name="$1" + local body="$2" + echo "Creating ${name} store type..." + response=$(curl -s -o /dev/null -w "%{http_code}" \ + -X POST "${BASE_URL}/certificatestoretypes" \ + -H "Content-Type: application/json" \ + -H "x-keyfactor-requested-with: APIClient" \ + "${CURL_AUTH[@]}" \ + -d "${body}") + if [ "$response" = "200" ] || [ "$response" = "201" ]; then + echo " OK (HTTP ${response})" + else + echo " FAILED (HTTP ${response})" + fi +} + +# --------------------------------------------------------------------------- +# Imperva — The URL that will be used as the base URL for Imperva endpoint calls. Should be https://my.imperva.com +# --------------------------------------------------------------------------- +create_store_type "Imperva" '{ + "Name": "Imperva", + "ShortName": "Imperva", + "Capability": "Imperva", + "ServerRequired": false, + "BlueprintAllowed": false, + "CustomAliasAllowed": "Required", + "PowerShell": false, + "PrivateKeyAllowed": "Required", + "SupportedOperations": { + "Add": true, + "Create": false, + "Discovery": false, + "Enrollment": false, + "Remove": true + }, + "PasswordOptions": { + "Style": "Default", + "EntrySupported": false, + "StoreRequired": true, + "StorePassword": { + "Description": "Your Imperva API id and API key concatenated with a comma (,}. For example: 12345,12345678-1234-1234-1234-123456789ABC. Please refer to the [Imperva documentation](https://docs.imperva.com/bundle/cloud-application-security/page/settings/api-keys.htm#:~:text=In%20the%20Cloud%20Security%20Console%20top%20menu%20bar%2C%20click%20Account,to%20create%20a%20new%20key.) as to how to create an API id and key.", + "IsPAMEligible": true + } + }, + "Properties": [], + "EntryParameters": [], + "StorePathDescription": "Your Imperva account id. Please refer to the [Imperva documentation](https://docs.imperva.com/howto/bd68301b) as to how to find your Imperva account id." +}' + + +echo "Completed." diff --git a/scripts/store_types/bash/kfutil_create_store_types.sh b/scripts/store_types/bash/kfutil_create_store_types.sh new file mode 100755 index 0000000..9c0558f --- /dev/null +++ b/scripts/store_types/bash/kfutil_create_store_types.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +# Creates all 1 store types using kfutil. +# kfutil reads definitions from the Keyfactor integration catalog. +# +# Auth environment variables (first matching method is used): +# OAuth access token: KEYFACTOR_AUTH_ACCESS_TOKEN +# OAuth client creds: KEYFACTOR_AUTH_CLIENT_ID + KEYFACTOR_AUTH_CLIENT_SECRET +# + KEYFACTOR_AUTH_TOKEN_URL +# Basic auth (AD): KEYFACTOR_HOSTNAME + KEYFACTOR_USERNAME + KEYFACTOR_PASSWORD +# + KEYFACTOR_DOMAIN +# +# Auto-generated by doctool generate-store-type-scripts — do not edit by hand. + +if ! command -v kfutil &> /dev/null; then + echo "kfutil could not be found. Please install kfutil" + echo "See https://github.com/Keyfactor/kfutil#quickstart" + exit 1 +fi + +if [ -z "$KEYFACTOR_HOSTNAME" ]; then + echo "KEYFACTOR_HOSTNAME not set — launching kfutil login" + kfutil login +fi + +kfutil store-types create --name "Imperva" + +echo "Done. All store types created." diff --git a/scripts/store_types/powershell/kfutil_create_store_types.ps1 b/scripts/store_types/powershell/kfutil_create_store_types.ps1 new file mode 100644 index 0000000..ada0c3e --- /dev/null +++ b/scripts/store_types/powershell/kfutil_create_store_types.ps1 @@ -0,0 +1,29 @@ +# Creates all 1 store types using kfutil. +# kfutil reads definitions from the Keyfactor integration catalog. +# +# Auth environment variables (first matching method is used): +# OAuth access token: KEYFACTOR_AUTH_ACCESS_TOKEN +# OAuth client creds: KEYFACTOR_AUTH_CLIENT_ID + KEYFACTOR_AUTH_CLIENT_SECRET +# + KEYFACTOR_AUTH_TOKEN_URL +# Basic auth (AD): KEYFACTOR_HOSTNAME + KEYFACTOR_USERNAME + KEYFACTOR_PASSWORD +# + KEYFACTOR_DOMAIN +# +# Auto-generated by doctool generate-store-type-scripts — do not edit by hand. + +# Uncomment if kfutil is not in your PATH +# Set-Alias -Name kfutil -Value 'C:\Program Files\Keyfactor\kfutil\kfutil.exe' + +if ($null -eq (Get-Command "kfutil" -ErrorAction SilentlyContinue)) { + Write-Host "kfutil could not be found. Please install kfutil" + Write-Host "See https://github.com/Keyfactor/kfutil#quickstart" + exit 1 +} + +if (-not $env:KEYFACTOR_HOSTNAME) { + Write-Host "KEYFACTOR_HOSTNAME not set — launching kfutil login" + & kfutil login +} + +& kfutil store-types create --name "Imperva" + +Write-Host "Done. All store types created." diff --git a/scripts/store_types/powershell/restmethod_create_store_types.ps1 b/scripts/store_types/powershell/restmethod_create_store_types.ps1 new file mode 100644 index 0000000..9fbe64c --- /dev/null +++ b/scripts/store_types/powershell/restmethod_create_store_types.ps1 @@ -0,0 +1,100 @@ +# Creates all 1 store types via the Keyfactor Command REST API +# using PowerShell Invoke-RestMethod. +# +# Authentication (first matching method is used): +# OAuth access token: KEYFACTOR_AUTH_ACCESS_TOKEN +# OAuth client creds: KEYFACTOR_AUTH_CLIENT_ID + KEYFACTOR_AUTH_CLIENT_SECRET +# + KEYFACTOR_AUTH_TOKEN_URL +# Basic auth (AD): KEYFACTOR_USERNAME + KEYFACTOR_PASSWORD + KEYFACTOR_DOMAIN +# +# Always required: +# KEYFACTOR_HOSTNAME Command hostname (e.g. my-command.example.com) +# +# Auto-generated by doctool generate-store-type-scripts — do not edit by hand. + +if (-not $env:KEYFACTOR_HOSTNAME) { + Write-Error "KEYFACTOR_HOSTNAME is required" + exit 1 +} + +$uri = "https://$($env:KEYFACTOR_HOSTNAME)/keyfactorapi/certificatestoretypes" +$headers = @{ + 'Content-Type' = "application/json" + 'x-keyfactor-requested-with' = "APIClient" +} + +# --------------------------------------------------------------------------- +# Resolve auth +# --------------------------------------------------------------------------- +if ($env:KEYFACTOR_AUTH_ACCESS_TOKEN) { + $headers['Authorization'] = "Bearer $($env:KEYFACTOR_AUTH_ACCESS_TOKEN)" +} elseif ($env:KEYFACTOR_AUTH_CLIENT_ID -and $env:KEYFACTOR_AUTH_CLIENT_SECRET -and $env:KEYFACTOR_AUTH_TOKEN_URL) { + Write-Host "Fetching OAuth token..." + $tokenBody = @{ + grant_type = 'client_credentials' + client_id = $env:KEYFACTOR_AUTH_CLIENT_ID + client_secret = $env:KEYFACTOR_AUTH_CLIENT_SECRET + } + $tokenResp = Invoke-RestMethod -Method Post -Uri $env:KEYFACTOR_AUTH_TOKEN_URL -Body $tokenBody + $headers['Authorization'] = "Bearer $($tokenResp.access_token)" +} elseif ($env:KEYFACTOR_USERNAME -and $env:KEYFACTOR_PASSWORD -and $env:KEYFACTOR_DOMAIN) { + $cred = [System.Convert]::ToBase64String( + [System.Text.Encoding]::ASCII.GetBytes( + "$($env:KEYFACTOR_USERNAME)@$($env:KEYFACTOR_DOMAIN):$($env:KEYFACTOR_PASSWORD)")) + $headers['Authorization'] = "Basic $cred" +} else { + Write-Error ("Authentication required. Set one of:`n" + + " KEYFACTOR_AUTH_ACCESS_TOKEN`n" + + " KEYFACTOR_AUTH_CLIENT_ID + KEYFACTOR_AUTH_CLIENT_SECRET + KEYFACTOR_AUTH_TOKEN_URL`n" + + " KEYFACTOR_USERNAME + KEYFACTOR_PASSWORD + KEYFACTOR_DOMAIN") + exit 1 +} + +function New-StoreType { + param([string]$Name, [string]$Body) + Write-Host "Creating $Name store type..." + try { + Invoke-RestMethod -Method Post -Uri $uri -Headers $headers -Body $Body -ContentType "application/json" | Out-Null + Write-Host " OK" + } catch { + Write-Warning " FAILED: $($_.Exception.Message)" + } +} + +# --------------------------------------------------------------------------- +# Imperva — The URL that will be used as the base URL for Imperva endpoint calls. Should be https://my.imperva.com +# --------------------------------------------------------------------------- +New-StoreType "Imperva" @' +{ + "Name": "Imperva", + "ShortName": "Imperva", + "Capability": "Imperva", + "ServerRequired": false, + "BlueprintAllowed": false, + "CustomAliasAllowed": "Required", + "PowerShell": false, + "PrivateKeyAllowed": "Required", + "SupportedOperations": { + "Add": true, + "Create": false, + "Discovery": false, + "Enrollment": false, + "Remove": true + }, + "PasswordOptions": { + "Style": "Default", + "EntrySupported": false, + "StoreRequired": true, + "StorePassword": { + "Description": "Your Imperva API id and API key concatenated with a comma (,}. For example: 12345,12345678-1234-1234-1234-123456789ABC. Please refer to the [Imperva documentation](https://docs.imperva.com/bundle/cloud-application-security/page/settings/api-keys.htm#:~:text=In%20the%20Cloud%20Security%20Console%20top%20menu%20bar%2C%20click%20Account,to%20create%20a%20new%20key.) as to how to create an API id and key.", + "IsPAMEligible": true + } + }, + "Properties": [], + "EntryParameters": [], + "StorePathDescription": "Your Imperva account id. Please refer to the [Imperva documentation](https://docs.imperva.com/howto/bd68301b) as to how to find your Imperva account id." +} +'@ + + +Write-Host "Completed."