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
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
package com.oneidentity.safeguard.safeguardjava;

import com.oneidentity.safeguard.safeguardjava.data.A2ARetrievableAccount;
import com.oneidentity.safeguard.safeguardjava.data.ApiKeySecret;
import com.oneidentity.safeguard.safeguardjava.data.BrokeredAccessRequest;
import com.oneidentity.safeguard.safeguardjava.data.KeyFormat;
import com.oneidentity.safeguard.safeguardjava.event.ISafeguardEventListener;
import com.oneidentity.safeguard.safeguardjava.exceptions.ArgumentException;
Expand Down Expand Up @@ -38,6 +35,15 @@ public interface ISafeguardA2AContext
*/
char[] retrievePassword(char[] apiKey) throws ObjectDisposedException, SafeguardForJavaException, ArgumentException;

/**
* Sets a password using Safeguard A2A.
*
* @param apiKey API key corresponding to the configured account.
* @param password Password to set.
* @return
*/
void SetPassword(char[] apiKey, char[] password) throws ObjectDisposedException, SafeguardForJavaException, ArgumentException;

/**
* Retrieves an SSH private key using Safeguard A2A.
*
Expand All @@ -61,6 +67,17 @@ public interface ISafeguardA2AContext
*/
List<IApiKeySecret> retrieveApiKeySecret(char[] apiKey) throws ObjectDisposedException, ArgumentException, SafeguardForJavaException;

/**
* Sets an SSH private key using Safeguard A2A.
*
* @param apiKey API key corresponding to the configured account.
* @param privateKey Private key to set.
* @param password Password associated with the private key.
* @param keyFormat Format to use when returning private key.
* @return
*/
void SetPrivateKey(char[] apiKey, char[] privateKey, char[] password, KeyFormat keyFormat) throws ObjectDisposedException, ArgumentException, SafeguardForJavaException;

/**
* Gets an A2A event listener. The handler passed in will be registered for the AssetAccountPasswordUpdated
* event, which is the only one supported in A2A. You just have to call Start(). The event listener returned
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
import com.oneidentity.safeguard.safeguardjava.data.ApiKeySecretInternal;
import com.oneidentity.safeguard.safeguardjava.data.BrokeredAccessRequest;
import com.oneidentity.safeguard.safeguardjava.data.CertificateContext;
import com.oneidentity.safeguard.safeguardjava.data.JsonBody;
import com.oneidentity.safeguard.safeguardjava.data.KeyFormat;
import com.oneidentity.safeguard.safeguardjava.data.SshKey;
import com.oneidentity.safeguard.safeguardjava.event.ISafeguardEventListener;
import com.oneidentity.safeguard.safeguardjava.event.SafeguardEventListener;
import com.oneidentity.safeguard.safeguardjava.exceptions.ArgumentException;
Expand Down Expand Up @@ -182,7 +184,42 @@ public char[] retrievePassword(char[] apiKey) throws ObjectDisposedException, Sa
Logger.getLogger(SafeguardA2AContext.class.getName()).log(Level.INFO, "Successfully retrieved A2A password.");
return password;
}


@Override
public void SetPassword(char[] apiKey, char[] password) throws ObjectDisposedException, SafeguardForJavaException, ArgumentException {
if (disposed) {
throw new ObjectDisposedException("SafeguardA2AContext");
}

if (apiKey == null) {
throw new ArgumentException("The apiKey parameter may not be null");
}

if (password == null) {
throw new ArgumentException("The password parameter may not be null");
}

Map<String, String> headers = new HashMap<>();
headers.put(HttpHeaders.AUTHORIZATION, String.format("A2A %s", new String(apiKey)));

Map<String, String> parameters = new HashMap<>();

CloseableHttpResponse response = a2AClient.execPUT("Credentials/Password", parameters, headers, null,
new JsonBody("\""+new String(password)+"\""), clientCertificate);

if (response == null) {
throw new SafeguardForJavaException(String.format("Unable to connect to web service %s", a2AClient.getBaseURL()));
}

String reply = Utils.getResponse(response);
if (!Utils.isSuccessful(response.getStatusLine().getStatusCode())) {
throw new SafeguardForJavaException("Error returned from Safeguard API, Error: "
+ String.format("%s %s", response.getStatusLine().getStatusCode(), reply));
}

Logger.getLogger(SafeguardA2AContext.class.getName()).log(Level.INFO, "Successfully set A2A password.");
}

@Override
public char[] retrievePrivateKey(char[] apiKey, KeyFormat keyFormat) throws ObjectDisposedException, ArgumentException, SafeguardForJavaException {
if (disposed) {
Expand Down Expand Up @@ -220,6 +257,54 @@ public char[] retrievePrivateKey(char[] apiKey, KeyFormat keyFormat) throws Obje
return privateKey;
}

@Override
public void SetPrivateKey(char[] apiKey, char[] privateKey, char[] password, KeyFormat keyFormat)
throws ObjectDisposedException, ArgumentException, SafeguardForJavaException {

if (disposed) {
throw new ObjectDisposedException("SafeguardA2AContext");
}

if (keyFormat == null)
keyFormat = KeyFormat.OpenSsh;

if (apiKey == null)
throw new ArgumentException("The apiKey parameter may not be null.");

if (privateKey == null)
throw new ArgumentException("The privateKey parameter may not be null");

if (password == null)
throw new ArgumentException("The password parameter may not be null");

SshKey sshKey = new SshKey();
sshKey.setPassphrase(new String(password));
sshKey.setPrivateKey(new String(privateKey));

String body = new Gson().toJson(sshKey);

Map<String, String> headers = new HashMap<>();
headers.put(HttpHeaders.AUTHORIZATION, String.format("A2A %s", new String(apiKey)));

Map<String, String> parameters = new HashMap<>();
parameters.put("keyFormat", keyFormat.name());

CloseableHttpResponse response = a2AClient.execPUT("Credentials/SshKey", parameters, headers, null, new JsonBody(body), clientCertificate);

if (response == null) {
throw new SafeguardForJavaException(String.format("Unable to connect to web service %s", a2AClient.getBaseURL()));
}

String reply = Utils.getResponse(response);
if (!Utils.isSuccessful(response.getStatusLine().getStatusCode())) {
throw new SafeguardForJavaException("Error returned from Safeguard API, Error: "
+ String.format("%s %s", response.getStatusLine().getStatusCode(), reply));
}

Logger.getLogger(SafeguardA2AContext.class.getName()).log(Level.INFO, "Successfully set A2A private key.");
return;
}

@Override
public List<IApiKeySecret> retrieveApiKeySecret(char[] apiKey) throws ObjectDisposedException, ArgumentException, SafeguardForJavaException {
if (disposed) {
Expand Down Expand Up @@ -439,5 +524,4 @@ private List<ApiKeySecretInternal> parseApiKeySecretResponse(String response) {

return null;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.oneidentity.safeguard.safeguardjava.data;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

/**
* This class is used to set the SshKey.
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class SshKey {

@JsonProperty("Passphrase")
private String passphrase;
@JsonProperty("PrivateKey")
private String privateKey;

public SshKey() {
}

public String getPassphrase() {
return passphrase;
}

public void setPassphrase(String passphrase) {
this.passphrase = passphrase;
}

public String getPrivateKey() {
return privateKey;
}

public void setPrivateKey(String privateKey) {
this.privateKey = privateKey;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,25 @@ public CloseableHttpResponse execPUT(String path, Map<String, String> queryParam
}
}

public CloseableHttpResponse execPUT(String path, Map<String, String> queryParams, Map<String, String> headers, Integer timeout,
JsonObject requestEntity, CertificateContext certificateContext) {
CloseableHttpClient certClient = getClientWithCertificate(certificateContext);

if (certClient != null) {
RequestBuilder rb = prepareRequest(RequestBuilder.put(getBaseURI(path)), queryParams, headers, timeout);

try {
String body = requestEntity.toJson();
rb.setEntity(new StringEntity(body == null ? "{}" : body));
CloseableHttpResponse r = certClient.execute(rb.build());
return r;
} catch (Exception ex) {
return null;
}
}
return null;
}

public CloseableHttpResponse execPOST(String path, Map<String, String> queryParams, Map<String, String> headers, Integer timeout, JsonObject requestEntity) {

RequestBuilder rb = prepareRequest(RequestBuilder.post(getBaseURI(path)), queryParams, headers, timeout);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,18 @@
import com.oneidentity.safeguard.safeguardjava.exceptions.ArgumentException;
import com.oneidentity.safeguard.safeguardjava.exceptions.ObjectDisposedException;
import com.oneidentity.safeguard.safeguardjava.exceptions.SafeguardForJavaException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class SafeguardTests {
Expand Down Expand Up @@ -315,6 +323,21 @@ ISafeguardA2AContext safeguardGetA2AContextByThumbprint() {
return a2aContext;
}

private byte[] readAllBytes(InputStream in) throws IOException {
ByteArrayOutputStream baos= new ByteArrayOutputStream();
byte[] buf = new byte[1024];
for (int read=0; read != -1; read = in.read(buf)) { baos.write(buf, 0, read); }
return baos.toByteArray();
}

private String formatPEM(String resource) throws IOException {
InputStream in = new ByteArrayInputStream(resource.getBytes());
String pem = new String(readAllBytes(in), StandardCharsets.ISO_8859_1);
Pattern parse = Pattern.compile("(?m)(?s)^---*BEGIN.*---*$(.*)^---*END.*---*$.*");
String encoded = parse.matcher(pem).replaceFirst("$1");
return encoded.replace("\r", "").replace("\n", "");
}

public void safeguardTestA2AContext(ISafeguardA2AContext a2aContext) {

if (a2aContext == null) {
Expand Down Expand Up @@ -351,19 +374,65 @@ else if (typeOfRelease.equalsIgnoreCase("a")) {
System.out.println(String.format("Invalid credential release type."));
return;
}
} catch (ArgumentException | ObjectDisposedException | SafeguardForJavaException ex) {
System.out.println("\t[ERROR]Test connection failed: " + ex.getMessage());
}
}

if (readLine("Test Setting Credential(y/n): ", "y").equalsIgnoreCase("y")) {
String typeOfRelease = readLine("Password, Private Key (p/k): ", "p");
String apiKey = readLine("API Key: ", null);

try {
if (typeOfRelease.equalsIgnoreCase("p")) {
String newPassword = readLine("New Password: ", "");
a2aContext.SetPassword(apiKey.toCharArray(), newPassword.toCharArray());

String password = new String(a2aContext.retrievePassword(apiKey.toCharArray()));
if (password.compareTo(newPassword) == 0)
System.out.println(String.format("\tSuccessfully set password"));
else
System.out.println(String.format("\tFailed to set password"));
}
else if (typeOfRelease.equalsIgnoreCase("k")) {
String privateKeyPath = readLine("Private Key File Path: ", "");
String privateKeyPassword = readLine("Private Key Password: ", "");
Path filePath = Paths.get(privateKeyPath).toAbsolutePath();
String privateKey = new String(Files.readAllBytes(filePath));

a2aContext.SetPrivateKey(apiKey.toCharArray(), privateKey.toCharArray(), privateKeyPassword.toCharArray(), KeyFormat.OpenSsh);

String key = new String(a2aContext.retrievePrivateKey(apiKey.toCharArray(), KeyFormat.OpenSsh));

String privkey1 = formatPEM(privateKey);
String privkey2 = formatPEM(key);

if (privkey1.compareTo(privkey2) == 0)
System.out.println(String.format("\tSuccessful private key release"));
else
System.out.println(String.format("\tFailed to set private key"));
}
else {
System.out.println(String.format("Invalid credential release type."));
return;
}
} catch (ArgumentException | ObjectDisposedException | SafeguardForJavaException | IOException ex) {
System.out.println("\t[ERROR]Test connection failed: " + ex.getMessage());
}
}

if (readLine("Test Access Request Broker(y/n): ", "y").equalsIgnoreCase("y")) {
try {
List<IA2ARetrievableAccount> registrations = a2aContext.getRetrievableAccounts();
System.out.println(String.format("\tRetrievable accounts:"));
for (IA2ARetrievableAccount reg : registrations) {
System.out.println(String.format("\t\tAssetId: %d AssetName: %s AccountId: %d AccountName: %s AccountDescription: %s",
reg.getAssetId(), reg.getAssetName(), reg.getAccountId(), reg.getAccountName(), reg.getAccountDescription()));
}
} catch (ArgumentException | ObjectDisposedException | SafeguardForJavaException ex) {
System.out.println("\t[ERROR]Test connection failed: " + ex.getMessage());
} catch (ObjectDisposedException | SafeguardForJavaException ex) {
System.out.println("\t[ERROR]Failed to get the retrievable accounts: " + ex.getMessage());
}
}

if (readLine("Test Access Request Broker(y/n): ", "y").equalsIgnoreCase("y")) {
String accountId = readLine("Account Id: ", null);
String assetId = readLine("Asset Id:", null);
String forUserId = readLine("For User Id:", null);
Expand Down