Skip to content

Commit 5b0471f

Browse files
authored
Merge pull request #155 from petrsnd/feature/petrsnd/filter-a2a-retrievable
Add support for filtering a2a retrievable accounts
2 parents 86483ff + f32940a commit 5b0471f

9 files changed

Lines changed: 574 additions & 4 deletions

File tree

AGENTS.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ pwsh -File Invoke-SafeguardTests.ps1 -ListSuites
224224

225225
| Suite | Tests | What it covers |
226226
|---|---|---|
227+
| A2ARetrievableAccounts | 6 | A2A retrievable account listing and SCIM filter support (requires test certs) |
227228
| AccessTokenAuth | 5 | Pre-obtained access token authentication |
228229
| AnonymousAccess | 3 | Unauthenticated Notification service access |
229230
| ApiInvocation | 12 | GET/POST/PUT/DELETE, filters, ordering, full responses |
@@ -278,6 +279,12 @@ echo '<password>' | java -jar $jar -a <appliance> -u admin -p -x --download-stre
278279
279280
# Streaming upload
280281
echo '<password>' | java -jar $jar -a <appliance> -u admin -p -x --upload-stream Appliance/Backups/Upload --upload-file backup.sgb
282+
283+
# A2A — list all retrievable accounts (certificate auth)
284+
echo '<cert-password>' | java -jar $jar -a <appliance> -c <pfx-file> -p -x --retrievable-accounts
285+
286+
# A2A — list retrievable accounts with SCIM filter
287+
echo '<cert-password>' | java -jar $jar -a <appliance> -c <pfx-file> -p -x --retrievable-accounts --filter "AccountName eq 'myaccount'"
281288
```
282289

283290
### Module-to-suite mapping
@@ -297,7 +304,7 @@ When you change a specific SDK module, run the relevant suite(s) rather than the
297304
| `SafeguardForPrivilegedSessions.java` | SpsIntegration (requires SPS appliance) |
298305
| `*Streaming*` classes | Streaming |
299306
| `event/` classes | (no automated suite yet — test manually) |
300-
| `SafeguardA2AContext.java` | (no automated suite yet — requires A2A app setup) |
307+
| `SafeguardA2AContext.java` | A2ARetrievableAccounts (requires test certs) |
301308

302309
### Fixing test failures
303310

@@ -663,6 +670,7 @@ Create `TestFramework/Suites/Suite-YourFeature.ps1` returning a hashtable:
663670
| Function | Purpose |
664671
|---|---|
665672
| `Invoke-SgJSafeguardApi` | Call Safeguard API via the test tool. Supports `-Service`, `-Method`, `-RelativeUrl`, `-Body`, `-Full`, `-Anonymous`, `-Pkce`, `-Username`, `-Password`, `-AccessToken` |
673+
| `Invoke-SgJSafeguardA2a` | List A2A retrievable accounts via certificate auth. Supports `-CertificateFile`, `-CertificatePassword`, `-Filter`, `-ParseJson` |
666674
| `Invoke-SgJTokenCommand` | Token operations: `GetToken`, `TokenLifetime`, `RefreshToken`, `Logout` |
667675
| `Test-SgJAssert` | Assert that a script block returns `$true` |
668676
| `Test-SgJAssertThrows` | Assert that a script block throws an error |

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,27 @@ specified passwords can be retrieved with a single method call without
5050
requiring access request workflow approvals. Safeguard A2A is protected by
5151
API keys and IP restrictions in addition to client certificate authentication.
5252

53+
### A2A Retrievable Accounts
54+
55+
You can list accounts available for A2A credential retrieval, and optionally
56+
filter them using a SCIM-style filter string (Safeguard v2.8+):
57+
58+
```Java
59+
ISafeguardA2AContext a2aContext = Safeguard.A2A.getContext("safeguard.sample.corp", "C:\\client.pfx", password, null, true);
60+
61+
// List all retrievable accounts
62+
List<IA2ARetrievableAccount> accounts = a2aContext.getRetrievableAccounts();
63+
64+
// Filter by account name (server-side SCIM filter)
65+
List<IA2ARetrievableAccount> filtered = a2aContext.getRetrievableAccounts("AccountName eq 'myServiceAccount'");
66+
67+
// Use the API key from a retrievable account to fetch the password
68+
char[] apiKey = accounts.get(0).getApiKey();
69+
char[] password = a2aContext.retrievePassword(apiKey);
70+
71+
a2aContext.dispose();
72+
```
73+
5374
SafeguardJava includes an SDK for listening to Safeguard's powerful, real-time
5475
event notification system. Safeguard provides role-based event notifications
5576
via SignalR to subscribed clients. If a Safeguard user is an Asset Administrator

TestFramework/SafeguardTestFramework.psm1

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,88 @@ function Invoke-SgJSafeguardSessions {
516516
return Invoke-SgJSafeguardTool -Arguments $toolArgs -StdinLine $Context.SpsPassword -ParseJson $ParseJson
517517
}
518518

519+
function Invoke-SgJSafeguardA2a {
520+
<#
521+
.SYNOPSIS
522+
Convenience wrapper for A2A operations via SafeguardJavaTool.
523+
.DESCRIPTION
524+
Creates an A2A context using a client certificate and performs one of:
525+
listing retrievable accounts (with optional SCIM filter), retrieving
526+
a password, or setting a password.
527+
#>
528+
[CmdletBinding()]
529+
param(
530+
[Parameter()]
531+
[PSCustomObject]$Context,
532+
533+
[Parameter(Mandatory)]
534+
[string]$CertificateFile,
535+
536+
[Parameter()]
537+
[string]$CertificatePassword,
538+
539+
[Parameter()]
540+
[string]$Filter,
541+
542+
[Parameter()]
543+
[string]$ApiKey,
544+
545+
[Parameter()]
546+
[switch]$RetrievePassword,
547+
548+
[Parameter()]
549+
[switch]$SetPassword,
550+
551+
[Parameter()]
552+
[string]$NewPassword,
553+
554+
[Parameter()]
555+
[bool]$ParseJson = $true
556+
)
557+
558+
if (-not $Context) { $Context = Get-SgJTestContext }
559+
560+
$stdinLines = @()
561+
562+
if ($RetrievePassword) {
563+
if (-not $ApiKey) { throw "Invoke-SgJSafeguardA2a: -ApiKey is required for -RetrievePassword" }
564+
$toolArgs = "-a $($Context.Appliance) -x --retrieve-password --api-key `"$ApiKey`" -c `"$CertificateFile`""
565+
if ($CertificatePassword) {
566+
$toolArgs += " -p"
567+
$stdinLines += $CertificatePassword
568+
}
569+
Write-Verbose "Invoke-SgJSafeguardA2a: retrieve-password"
570+
$stdinLine = if ($stdinLines.Count -gt 0) { $stdinLines -join "`n" } else { $null }
571+
return Invoke-SgJSafeguardTool -Arguments $toolArgs -StdinLine $stdinLine -ParseJson $false
572+
}
573+
elseif ($SetPassword) {
574+
if (-not $ApiKey) { throw "Invoke-SgJSafeguardA2a: -ApiKey is required for -SetPassword" }
575+
if (-not $NewPassword) { throw "Invoke-SgJSafeguardA2a: -NewPassword is required for -SetPassword" }
576+
$toolArgs = "-a $($Context.Appliance) -x --set-password --api-key `"$ApiKey`" -c `"$CertificateFile`""
577+
if ($CertificatePassword) {
578+
$toolArgs += " -p"
579+
$stdinLines += $CertificatePassword
580+
}
581+
$stdinLines += $NewPassword
582+
Write-Verbose "Invoke-SgJSafeguardA2a: set-password"
583+
$stdinLine = $stdinLines -join "`n"
584+
return Invoke-SgJSafeguardTool -Arguments $toolArgs -StdinLine $stdinLine -ParseJson $false
585+
}
586+
else {
587+
$toolArgs = "-a $($Context.Appliance) -x --retrievable-accounts -c `"$CertificateFile`""
588+
if ($CertificatePassword) {
589+
$toolArgs += " -p"
590+
$stdinLines += $CertificatePassword
591+
}
592+
if ($Filter) {
593+
$toolArgs += " --filter `"$Filter`""
594+
}
595+
Write-Verbose "Invoke-SgJSafeguardA2a: retrievable-accounts"
596+
$stdinLine = if ($stdinLines.Count -gt 0) { $stdinLines -join "`n" } else { $null }
597+
return Invoke-SgJSafeguardTool -Arguments $toolArgs -StdinLine $stdinLine -ParseJson $ParseJson
598+
}
599+
}
600+
519601
function Test-SgJSpsConfigured {
520602
<#
521603
.SYNOPSIS

0 commit comments

Comments
 (0)