Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions .github/workflows/dotnet-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name: Build and Test

on:
pull_request:
push:
branches:
- main
- release-*

jobs:
unit-test:
name: Build and Unit Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.x'

- name: Add Keyfactor NuGet feed
run: dotnet nuget add source https://nuget.pkg.github.com/Keyfactor/index.json -n github -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text

- name: Build
run: dotnet build delinea-secretserver-pam.sln -c Release

- name: Unit Test
# No SECRET_SERVER_* env vars set — IntegrationFactAttribute auto-skips integration tests
run: dotnet test delinea-secretserver-pam.Tests/delinea-secretserver-pam.Tests.csproj --no-build -c Release --logger "console;verbosity=normal"

integration-test:
name: Integration Test
runs-on: ubuntu-latest
needs: unit-test
# Skipped entirely when the environment hasn't been provisioned via Terraform
if: vars.INTEGRATION_TESTS_ENABLED == 'true'
environment: integration-tests
steps:
- uses: actions/checkout@v4

- uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.x'

- name: Add Keyfactor NuGet feed
run: dotnet nuget add source https://nuget.pkg.github.com/Keyfactor/index.json -n github -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text

- name: Build
run: dotnet build delinea-secretserver-pam.sln -c Release

- name: Integration Test
run: dotnet test delinea-secretserver-pam.Tests/delinea-secretserver-pam.Tests.csproj --no-build -c Release --logger "console;verbosity=normal"
env:
SECRET_SERVER_URL: ${{ secrets.SECRET_SERVER_URL }}
SECRET_SERVER_USERNAME: ${{ secrets.SECRET_SERVER_USERNAME }}
SECRET_SERVER_PASSWORD: ${{ secrets.SECRET_SERVER_PASSWORD }}
SECRET_SERVER_SECRET_ID: ${{ secrets.SECRET_SERVER_SECRET_ID }}
SECRET_SERVER_SKIP_TLS_VALIDATION: ${{ vars.SECRET_SERVER_SKIP_TLS_VALIDATION }}
KEYFACTOR_PAM_SKIP_TLS_VALIDATION: ${{ vars.SECRET_SERVER_SKIP_TLS_VALIDATION }}
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,7 @@ obj/
riderModule.iml
/_ReSharper.Caches/
.idea/*
.vs/
.vs/
.env
scripts/
client_pam.jsonterraform/
54 changes: 53 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,55 @@
# v1.3.0

## Features

- Added three grant-type-specific PAM type variants. Each type exposes only the fields relevant to its authentication flow, resolving the Keyfactor Command UI requirement that all declared fields be populated.
- `Delinea-SecretServer-Password` — Username + Password authentication. Server parameters: `Host`, `Username`, `Password`, `SkipTlsValidation`.
- `Delinea-SecretServer-ClientCredentials` — OAuth2 client credentials flow. Server parameters: `Host`, `ClientId`, `ClientSecret`, `SkipTlsValidation`.
- `Delinea-SecretServer-Windows` — Integrated Windows Authentication (IWA). Server parameters: `Host`, `SkipTlsValidation`. NOTE: IWA is not supported on Secret Server Cloud.
- All shared logic (HTTP, validation, secret retrieval, audit logging) is implemented once in the new `SecretServerPamBase` abstract class.
- The existing `Delinea-SecretServer` type is unchanged and fully backwards compatible.
- TLS certificate validation can now be disabled via the `KEYFACTOR_PAM_SKIP_TLS_VALIDATION` environment variable (`true` or `1`), in addition to the existing `SkipTlsValidation` configuration parameter. Either setting is sufficient to disable validation.
- Parameter values of `N/A` (case-insensitive, whitespace-trimmed) are now treated as empty/absent. This allows users of the backwards-compatible `Delinea-SecretServer` type to enter `N/A` as a dummy value in the Keyfactor Command UI for fields that are not applicable to their authentication flow.

## Compliance Remediation (SOX/SOC2)

- `GetDelineaSecretAsync` now throws `InvalidSecretConfigurationException` when the requested field is not found in the secret, rather than silently returning an empty string. This prevents silent credential resolution failures from going undetected.
- Token endpoint error response body is now truncated to 500 characters before logging to prevent secret metadata exposure in log sinks.
- Added an explicit `LogInformation` audit event for the Windows authentication path recording OS identity, machine name, target URL, and SecretId before the HTTP call is made.
- Added an authentication success `LogInformation` event in `GetAccessToken` recording the caller identity and target URL with a structured `AuthenticationResult=Success` field.
- A `Guid`-based correlation ID is generated at the start of each `GetPassword` invocation and threaded as a trailing structured field through all `LogInformation` and `LogError` calls in `GetDelineaSecretAsync` and `GetAccessToken`, enabling log correlation across a full PAM operation.
- `Stopwatch` instances for the token POST and secret GET HTTP calls are now declared outside their try blocks; catch blocks record elapsed duration and emit a structured `HTTP call failed` log event so network failure timing is preserved in exception paths.
- Removed the duplicate `SecretResponse` class defined inline at the bottom of `SecretServerPam.cs`. The canonical definition in `Models/SecretResponse.cs` (which includes `Id`, `Name`, `SecretTemplateId`, `FolderId`, and `Active` in addition to `Items`) is now the sole definition, resolved via the existing `using Keyfactor.Extensions.Pam.Delinea.Models;` import.
- `Username` and `ClientId` parameters in `integration-manifest.json` changed from `DataType: 2` (secret/masked) to `DataType: 1` (plain text). These are non-secret identifiers and should not be stored or displayed as secrets in the Keyfactor Command UI.
- Added inline comments at each `Environment.UserName` usage site documenting that this value reflects the OS service account identity, not the Keyfactor Command caller identity, since `IPAMProvider` does not expose caller context.

## Improvements

- Enhanced debug logging for token endpoint requests: the obfuscated request body (credentials redacted) and raw response body are now logged on token request failures to aid troubleshooting.
- Added structured audit log event on every `GetPassword` invocation recording caller identity, machine name, target URL, grant type, SecretId, and field name.
- Added response duration logging (ms) for both the OAuth token endpoint and secret retrieval API calls.
- Success and failure log events now include SecretId, field name, grant type, and URL for complete audit trail.
- Auth failure log events now include the target URL, grant type, and caller identity.
- Error responses from Secret Server are truncated to 500 characters before logging to prevent sensitive metadata exposure.
- Removed raw token response body from deserialization failure log path to prevent accidental bearer token exposure.

## Bug Fixes

- Fixed `client_credentials` case in `BuildDelineaConfiguration` where `GrantType` was incorrectly set to `"password"` instead of `"client_credentials"` on the resulting `DelineaConfiguration` object.
- Validation of `SecretFieldName` now rejects whitespace-only values (previously only empty string was rejected).
- Replaced `.Result` with `.GetAwaiter().GetResult()` in `GetPassword` to prevent exception masking on async task failures.

## Testing

- Replaced the manual `TestConsole` project with a proper `xUnit` test project (`delinea-secretserver-pam.Tests`, targeting `net8.0`) covering all four PAM types, all auth flows, and error paths including missing parameters, token failures, field-not-found, and non-success HTTP responses.
- Integration tests skip automatically when `SECRET_SERVER_*` environment variables are not set.

## Maintenance

- Removed dead `IValidatableObject` implementation from `DelineaConfiguration`; validation is enforced in `ValidateServerConfigurationParams`.
- Masked password value in TestConsole output.
- Bumped TestConsole target framework to net10.0 and global SDK pin to 10.0.0.

# v1.2.0

## Features
Expand All @@ -9,4 +61,4 @@
- Added support for `client_credential` grant type for OAuth2 authentication.

# v1.0.0
- Initial release of Delinea SecretServer PAM Provider
- Initial release of Delinea SecretServer PAM Provider
Loading
Loading