Skip to content

Commit aa58b28

Browse files
committed
Add tests for password retrieval and udpate
1 parent 25c356d commit aa58b28

4 files changed

Lines changed: 143 additions & 29 deletions

File tree

TestFramework/SafeguardTestFramework.psm1

Lines changed: 52 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -519,10 +519,11 @@ function Invoke-SgJSafeguardSessions {
519519
function Invoke-SgJSafeguardA2a {
520520
<#
521521
.SYNOPSIS
522-
Convenience wrapper for listing A2A retrievable accounts via SafeguardJavaTool.
522+
Convenience wrapper for A2A operations via SafeguardJavaTool.
523523
.DESCRIPTION
524-
Creates an A2A context using a client certificate and retrieves retrievable accounts,
525-
optionally applying a server-side SCIM filter.
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.
526527
#>
527528
[CmdletBinding()]
528529
param(
@@ -538,26 +539,63 @@ function Invoke-SgJSafeguardA2a {
538539
[Parameter()]
539540
[string]$Filter,
540541

542+
[Parameter()]
543+
[string]$ApiKey,
544+
545+
[Parameter()]
546+
[switch]$RetrievePassword,
547+
548+
[Parameter()]
549+
[switch]$SetPassword,
550+
551+
[Parameter()]
552+
[string]$NewPassword,
553+
541554
[Parameter()]
542555
[bool]$ParseJson = $true
543556
)
544557

545558
if (-not $Context) { $Context = Get-SgJTestContext }
546559

547-
$toolArgs = "-a $($Context.Appliance) -x --retrievable-accounts -c `"$CertificateFile`""
560+
$stdinLines = @()
548561

549-
if ($CertificatePassword) {
550-
$toolArgs += " -p"
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
551572
}
552-
553-
if ($Filter) {
554-
$toolArgs += " --filter `"$Filter`""
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
555598
}
556-
557-
Write-Verbose "Invoke-SgJSafeguardA2a: $toolArgs"
558-
559-
$stdinLine = if ($CertificatePassword) { $CertificatePassword } else { $null }
560-
return Invoke-SgJSafeguardTool -Arguments $toolArgs -StdinLine $stdinLine -ParseJson $ParseJson
561599
}
562600

563601
function Test-SgJSpsConfigured {

TestFramework/Suites/Suite-A2ARetrievableAccounts.ps1

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@
164164
-RelativeUrl "AssetAccounts/$($account.Id)/Password" `
165165
-Username $adminUser -Password $adminPassword `
166166
-Body "'TestA2aPassword123!'" -ParseJson $false
167+
$Context.SuiteData["AccountPassword"] = "TestA2aPassword123!"
167168

168169
# 9. Create A2A registration linked to certificate user
169170
Write-Host " Creating A2A registration '$regName'..." -ForegroundColor DarkGray
@@ -224,11 +225,16 @@
224225
Test-SgJSkip "Filter with no matches returns empty list" "Test certificates not found"
225226
Test-SgJSkip "Invalid filter property gives useful error" "Test certificates not found"
226227
Test-SgJSkip "Malformed filter expression gives useful error" "Test certificates not found"
228+
Test-SgJSkip "A2A retrieve password via PFX" "Test certificates not found"
229+
Test-SgJSkip "A2A set password via PFX and verify" "Test certificates not found"
230+
Test-SgJSkip "A2A retrieve password with bad API key fails" "Test certificates not found"
227231
return
228232
}
229233

230234
$accountName = $Context.SuiteData["AccountName"]
231235
$accountId = $Context.SuiteData["AccountId"]
236+
$apiKey = $Context.SuiteData["ApiKey"]
237+
$originalPassword = $Context.SuiteData["AccountPassword"]
232238

233239
# --- Unfiltered listing ---
234240

@@ -301,6 +307,44 @@
301307
}
302308
$threw
303309
}
310+
311+
# --- Credential retrieval ---
312+
313+
Test-SgJAssert "A2A retrieve password via PFX" {
314+
$result = Invoke-SgJSafeguardA2a -Context $Context `
315+
-CertificateFile $Context.UserPfx -CertificatePassword "a" `
316+
-ApiKey $apiKey -RetrievePassword
317+
$result.Trim() -eq $originalPassword
318+
}
319+
320+
Test-SgJAssert "A2A set password via PFX and verify" {
321+
$updatedPassword = "UpdatedA2aPass456!@#"
322+
Invoke-SgJSafeguardA2a -Context $Context `
323+
-CertificateFile $Context.UserPfx -CertificatePassword "a" `
324+
-ApiKey $apiKey -SetPassword -NewPassword $updatedPassword
325+
$retrieved = Invoke-SgJSafeguardA2a -Context $Context `
326+
-CertificateFile $Context.UserPfx -CertificatePassword "a" `
327+
-ApiKey $apiKey -RetrievePassword
328+
$retrieved.Trim() -eq $updatedPassword
329+
}
330+
331+
Test-SgJAssert "A2A retrieve password with bad API key fails" {
332+
$threw = $false
333+
try {
334+
Invoke-SgJSafeguardA2a -Context $Context `
335+
-CertificateFile $Context.UserPfx -CertificatePassword "a" `
336+
-ApiKey "00000000-0000-0000-0000-000000000000" -RetrievePassword
337+
}
338+
catch {
339+
$threw = ($_.Exception.Message -match "404" -or
340+
$_.Exception.Message -match "NotFound" -or
341+
$_.Exception.Message -match "not found" -or
342+
$_.Exception.Message -match "403" -or
343+
$_.Exception.Message -match "Forbidden" -or
344+
$_.Exception.Message -match "Error")
345+
}
346+
$threw
347+
}
304348
}
305349

306350
Cleanup = {

tests/safeguardjavaclient/src/main/java/com/oneidentity/safeguard/safeguardclient/SafeguardJavaClient.java

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ public static void main(String[] args) {
6767
return;
6868
}
6969

70-
if (opts.retrievableAccounts) {
71-
handleRetrievableAccounts(opts);
70+
if (opts.retrievableAccounts || opts.retrievePassword || opts.setPassword) {
71+
handleA2aOperation(opts);
7272
System.exit(0);
7373
return;
7474
}
@@ -178,35 +178,55 @@ private static String handleStreamingRequest(ToolOptions opts, ISafeguardConnect
178178
}
179179
}
180180

181-
private static void handleRetrievableAccounts(ToolOptions opts) throws Exception {
182-
char[] password = null;
181+
private static void handleA2aOperation(ToolOptions opts) throws Exception {
182+
Scanner stdinScanner = new Scanner(System.in);
183+
184+
char[] certPassword = null;
183185
if (opts.readPassword) {
184186
System.err.print("Password: ");
185-
password = new Scanner(System.in).nextLine().toCharArray();
187+
certPassword = stdinScanner.nextLine().toCharArray();
186188
}
187189

188190
ISafeguardA2AContext a2aContext;
189191
if (opts.certificateFile != null) {
190192
System.err.println("Creating A2A context for " + opts.appliance + " with certificate file " + opts.certificateFile);
191-
a2aContext = Safeguard.A2A.getContext(opts.appliance, opts.certificateFile, password, null, opts.insecure);
193+
a2aContext = Safeguard.A2A.getContext(opts.appliance, opts.certificateFile, certPassword, null, opts.insecure);
192194
} else if (opts.thumbprint != null) {
193195
System.err.println("Creating A2A context for " + opts.appliance + " with thumbprint " + opts.thumbprint);
194196
a2aContext = Safeguard.A2A.getContext(opts.appliance, opts.thumbprint, null, opts.insecure);
195197
} else {
196198
throw new IllegalArgumentException(
197-
"--retrievable-accounts requires a certificate (-c or -t).");
199+
"A2A operations require a certificate (-c or -t).");
198200
}
199201

200202
try {
201-
List<IA2ARetrievableAccount> accounts;
202-
if (opts.filter != null && opts.filter.length() > 0) {
203-
System.err.println("Retrieving accounts with filter: " + opts.filter);
204-
accounts = a2aContext.getRetrievableAccounts(opts.filter);
205-
} else {
206-
System.err.println("Retrieving all accounts");
207-
accounts = a2aContext.getRetrievableAccounts();
203+
if (opts.retrievableAccounts) {
204+
List<IA2ARetrievableAccount> accounts;
205+
if (opts.filter != null && opts.filter.length() > 0) {
206+
System.err.println("Retrieving accounts with filter: " + opts.filter);
207+
accounts = a2aContext.getRetrievableAccounts(opts.filter);
208+
} else {
209+
System.err.println("Retrieving all accounts");
210+
accounts = a2aContext.getRetrievableAccounts();
211+
}
212+
System.out.println(mapper.writeValueAsString(accounts));
213+
} else if (opts.retrievePassword) {
214+
if (opts.apiKey == null || opts.apiKey.length() == 0) {
215+
throw new IllegalArgumentException("--retrieve-password requires --api-key");
216+
}
217+
System.err.println("Retrieving password via A2A");
218+
char[] password = a2aContext.retrievePassword(opts.apiKey.toCharArray());
219+
System.out.println(new String(password));
220+
} else if (opts.setPassword) {
221+
if (opts.apiKey == null || opts.apiKey.length() == 0) {
222+
throw new IllegalArgumentException("--set-password requires --api-key");
223+
}
224+
System.err.print("New password: ");
225+
char[] newPassword = stdinScanner.nextLine().toCharArray();
226+
System.err.println("Setting password via A2A");
227+
a2aContext.SetPassword(opts.apiKey.toCharArray(), newPassword);
228+
System.out.println("OK");
208229
}
209-
System.out.println(mapper.writeValueAsString(accounts));
210230
} finally {
211231
a2aContext.dispose();
212232
}

tests/safeguardjavaclient/src/main/java/com/oneidentity/safeguard/safeguardclient/ToolOptions.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,18 @@ public class ToolOptions {
111111
description = "SCIM-style filter for A2A retrievable accounts (e.g. \"AccountName eq 'admin'\")")
112112
String filter;
113113

114+
@Option(names = {"--retrieve-password"}, defaultValue = "false",
115+
description = "Retrieve a password via A2A (requires -c or -t, and --api-key)")
116+
boolean retrievePassword;
117+
118+
@Option(names = {"--set-password"}, defaultValue = "false",
119+
description = "Set a password via A2A (requires -c or -t, --api-key, and --new-password via stdin)")
120+
boolean setPassword;
121+
122+
@Option(names = {"--api-key"},
123+
description = "A2A API key for credential retrieval or set operations")
124+
String apiKey;
125+
114126
@Option(names = {"--sps"}, defaultValue = "false",
115127
description = "Connect to Safeguard for Privileged Sessions (SPS) instead of SPP")
116128
boolean sps;

0 commit comments

Comments
 (0)