From 6ff72bd68f718b3c5479c7db43fcf51acc3f69c4 Mon Sep 17 00:00:00 2001 From: Brad Nicholes Date: Fri, 24 Sep 2021 16:50:51 -0600 Subject: [PATCH] Add APIs for connecting to SPS. Update the dependency versions. Move to 6.11 and sync with SafeguardDotnet. --- pom.xml | 14 +- .../safeguardjava/ISafeguardConnection.java | 15 ++ .../ISafeguardSessionsConnection.java | 45 +++++ .../PersistentSafeguardConnection.java | 86 ++++++++++ .../safeguard/safeguardjava/Safeguard.java | 15 +- .../safeguardjava/SafeguardConnection.java | 21 +++ .../SafeguardForPrivilegedSessions.java | 34 ++++ .../SafeguardSessionsConnection.java | 155 ++++++++++++++++++ .../safeguardjava/data/JoinRequest.java | 47 ++++++ .../safeguardjava/restclient/RestClient.java | 90 +++++++++- tests/safeguardjavaclient/pom.xml | 2 +- .../safeguardclient/SafeguardJavaClient.java | 10 ++ .../safeguardclient/SafeguardTests.java | 46 ++++++ 13 files changed, 567 insertions(+), 13 deletions(-) create mode 100644 src/main/java/com/oneidentity/safeguard/safeguardjava/ISafeguardSessionsConnection.java create mode 100644 src/main/java/com/oneidentity/safeguard/safeguardjava/PersistentSafeguardConnection.java create mode 100644 src/main/java/com/oneidentity/safeguard/safeguardjava/SafeguardForPrivilegedSessions.java create mode 100644 src/main/java/com/oneidentity/safeguard/safeguardjava/SafeguardSessionsConnection.java create mode 100644 src/main/java/com/oneidentity/safeguard/safeguardjava/data/JoinRequest.java diff --git a/pom.xml b/pom.xml index 76e3331..5bcd291 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ UTF-8 - 6.10.0-SNAPSHOT + 6.11.0-SNAPSHOT ./signingcert.pfx 1 secret @@ -42,33 +42,33 @@ com.squareup.okhttp3 okhttp - 3.11.0 + 4.9.1 com.microsoft.signalr signalr - 5.0.1 + 5.0.10 org.apache.httpcomponents httpclient - [4.5.13,) + 4.5.13 com.fasterxml.jackson.core jackson-databind - 2.9.10.8 + 2.12.5 jar org.slf4j slf4j-api - 1.7.25 + 1.7.32 com.google.code.gson gson - 2.8.5 + 2.8.8 diff --git a/src/main/java/com/oneidentity/safeguard/safeguardjava/ISafeguardConnection.java b/src/main/java/com/oneidentity/safeguard/safeguardjava/ISafeguardConnection.java index c1c95e3..af6846a 100644 --- a/src/main/java/com/oneidentity/safeguard/safeguardjava/ISafeguardConnection.java +++ b/src/main/java/com/oneidentity/safeguard/safeguardjava/ISafeguardConnection.java @@ -100,6 +100,21 @@ String invokeMethodCsv(Service service, Method method, String relativeUrl, Map additionalHeaders, Integer timeout) throws ObjectDisposedException, SafeguardForJavaException, ArgumentException; + /** + * Join a Safeguard for Privileged Sessions and a Safeguard appliance. The Safeguard for + * Privileged Sessions appliance needs to enable clustering and be a central search node. + * + * @param spsConnection A connection to the SafeguardForPrivilegedSessions appliance. + * @param certificateChain The PEM certificate chain of the Safeguard web api. + * @param sppAddress The address of the Safeguard appliance. + * @returns Response with status code, headers, and body as string. + * @throws ObjectDisposedException Object has already been disposed. + * @throws SafeguardForJavaException General Safeguard for Java exception. + * @throws ArgumentException Invalid argument. + */ + FullResponse JoinSps(ISafeguardSessionsConnection spsConnection, String certificateChain, String sppAddress) + throws ObjectDisposedException, SafeguardForJavaException, ArgumentException; + /** * Provides support for HTTP streaming requests * @return IStreamingRequest diff --git a/src/main/java/com/oneidentity/safeguard/safeguardjava/ISafeguardSessionsConnection.java b/src/main/java/com/oneidentity/safeguard/safeguardjava/ISafeguardSessionsConnection.java new file mode 100644 index 0000000..b582a87 --- /dev/null +++ b/src/main/java/com/oneidentity/safeguard/safeguardjava/ISafeguardSessionsConnection.java @@ -0,0 +1,45 @@ +package com.oneidentity.safeguard.safeguardjava; + +import com.oneidentity.safeguard.safeguardjava.data.FullResponse; +import com.oneidentity.safeguard.safeguardjava.data.Method; +import com.oneidentity.safeguard.safeguardjava.exceptions.ArgumentException; +import com.oneidentity.safeguard.safeguardjava.exceptions.ObjectDisposedException; +import com.oneidentity.safeguard.safeguardjava.exceptions.SafeguardForJavaException; + +/** + * This is the reusable connection interface that can be used to call SPS API. + */ +public interface ISafeguardSessionsConnection { + + /** + * Call a Safeguard for Privileged Sessions API method and get any response as a string. + * If there is a failure a SafeguardDotNetException will be thrown. + * + * @param method Safeguard method type to use. + * @param relativeUrl Relative URL of the service to use. + * @param body Request body to pass to the method. + * @return Response body as a string. + * @throws ObjectDisposedException Object has already been disposed. + * @throws SafeguardForJavaException General Safeguard for Java exception. + * @throws ArgumentException Invalid argument. + */ + String InvokeMethod(Method method, String relativeUrl, String body) + throws ObjectDisposedException, SafeguardForJavaException, ArgumentException; + + /** + * Call a Safeguard for Privileged Sessions API method and get a detailed response + * with status code, headers, and body. If there is a failure a SafeguardDotNetException + * will be thrown. + * + * @param method Safeguard method type to use. + * @param relativeUrl Relative URL of the service to use. + * @param body Request body to pass to the method. + * @return Response with status code, headers, and body as string. + * @throws ObjectDisposedException Object has already been disposed. + * @throws SafeguardForJavaException General Safeguard for Java exception. + * @throws ArgumentException Invalid argument. + */ + FullResponse InvokeMethodFull(Method method, String relativeUrl, String body) + throws ObjectDisposedException, SafeguardForJavaException, ArgumentException; + +} diff --git a/src/main/java/com/oneidentity/safeguard/safeguardjava/PersistentSafeguardConnection.java b/src/main/java/com/oneidentity/safeguard/safeguardjava/PersistentSafeguardConnection.java new file mode 100644 index 0000000..d782b2f --- /dev/null +++ b/src/main/java/com/oneidentity/safeguard/safeguardjava/PersistentSafeguardConnection.java @@ -0,0 +1,86 @@ +package com.oneidentity.safeguard.safeguardjava; + +import com.oneidentity.safeguard.safeguardjava.data.FullResponse; +import com.oneidentity.safeguard.safeguardjava.data.Method; +import com.oneidentity.safeguard.safeguardjava.data.Service; +import com.oneidentity.safeguard.safeguardjava.event.ISafeguardEventListener; +import com.oneidentity.safeguard.safeguardjava.event.SafeguardEventListener; +import com.oneidentity.safeguard.safeguardjava.exceptions.ArgumentException; +import com.oneidentity.safeguard.safeguardjava.exceptions.ObjectDisposedException; +import com.oneidentity.safeguard.safeguardjava.exceptions.SafeguardForJavaException; +import java.util.Map; + +class PersistentSafeguardConnection implements ISafeguardConnection { + + private final ISafeguardConnection _connection; + private boolean disposed; + + public PersistentSafeguardConnection(ISafeguardConnection connection) { + _connection = connection; + } + + public IStreamingRequest getStreamingRequest() { + return _connection.getStreamingRequest(); + } + + @Override + public void dispose() + { + _connection.dispose(); + } + + public FullResponse JoinSps(ISafeguardSessionsConnection spsConnection, String certificateChain, String sppAddress) + throws ObjectDisposedException, SafeguardForJavaException, ArgumentException + { + if (_connection.getAccessTokenLifetimeRemaining() <= 0) + _connection.refreshAccessToken(); + return _connection.JoinSps(spsConnection, certificateChain, sppAddress); + } + + @Override + public int getAccessTokenLifetimeRemaining() throws ObjectDisposedException, SafeguardForJavaException { + return _connection.getAccessTokenLifetimeRemaining(); + } + + @Override + public void refreshAccessToken() throws ObjectDisposedException, SafeguardForJavaException { + _connection.refreshAccessToken(); + } + + @Override + public String invokeMethod(Service service, Method method, String relativeUrl, String body, Map parameters, Map additionalHeaders, Integer timeout) throws ObjectDisposedException, SafeguardForJavaException, ArgumentException { + if(_connection.getAccessTokenLifetimeRemaining() <= 0) + _connection.refreshAccessToken(); + return _connection.invokeMethod(service, method, relativeUrl, body, parameters, additionalHeaders, timeout); + } + + @Override + public FullResponse invokeMethodFull(Service service, Method method, String relativeUrl, String body, Map parameters, Map additionalHeaders, Integer timeout) throws ObjectDisposedException, SafeguardForJavaException, ArgumentException { + if (_connection.getAccessTokenLifetimeRemaining() <= 0) + _connection.refreshAccessToken(); + return _connection.invokeMethodFull(service, method, relativeUrl, body, parameters, additionalHeaders, timeout); + } + + @Override + public String invokeMethodCsv(Service service, Method method, String relativeUrl, String body, Map parameters, Map additionalHeaders, Integer timeout) throws ObjectDisposedException, SafeguardForJavaException, ArgumentException { + if (_connection.getAccessTokenLifetimeRemaining() <= 0) + _connection.refreshAccessToken(); + return _connection.invokeMethodCsv(service, method, relativeUrl, body, parameters, additionalHeaders, timeout); + } + + @Override + public SafeguardEventListener getEventListener() throws ObjectDisposedException, ArgumentException { + return _connection.getEventListener(); + } + + @Override + public ISafeguardEventListener getPersistentEventListener() throws ObjectDisposedException, SafeguardForJavaException { + return _connection.getPersistentEventListener(); + } + + @Override + public void logOut() throws ObjectDisposedException { + _connection.logOut(); + } + +} diff --git a/src/main/java/com/oneidentity/safeguard/safeguardjava/Safeguard.java b/src/main/java/com/oneidentity/safeguard/safeguardjava/Safeguard.java index 94eea45..1207663 100644 --- a/src/main/java/com/oneidentity/safeguard/safeguardjava/Safeguard.java +++ b/src/main/java/com/oneidentity/safeguard/safeguardjava/Safeguard.java @@ -655,7 +655,7 @@ public static ISafeguardConnection connect(String networkAddress, byte[] certifi * @param apiVersion API version. * @param ignoreSsl If set to true ignore ssl. * - * @return The connect. + * @return Reusable Safeguard API connection. * @throws SafeguardForJavaException General Safeguard for Java exception. */ public static ISafeguardConnection connect(String networkAddress, Integer apiVersion, Boolean ignoreSsl) @@ -682,7 +682,7 @@ public static ISafeguardConnection connect(String networkAddress, Integer apiVer * @param apiVersion API version. * @param validationCallback Callback function to be executed during SSL certificate validation. * - * @return The connect. + * @return Reusable Safeguard API connection. * @throws SafeguardForJavaException General Safeguard for Java exception. */ public static ISafeguardConnection connect(String networkAddress, HostnameVerifier validationCallback, Integer apiVersion) @@ -697,6 +697,17 @@ public static ISafeguardConnection connect(String networkAddress, HostnameVerifi return new SafeguardConnection(new AnonymousAuthenticator(networkAddress, version, false, validationCallback)); } + /** + * Create a persistent connection to the Safeguard API that automatically renews expired access tokens. + * + * @param connection Connection to be made persistent. + * @return Reusable persistent Safeguard API connection. + */ + public static ISafeguardConnection Persist(ISafeguardConnection connection) + { + return new PersistentSafeguardConnection(connection); + } + /** * This static class provides access to Safeguard Event functionality with * persistent event listeners. Persistent event listeners can handle longer diff --git a/src/main/java/com/oneidentity/safeguard/safeguardjava/SafeguardConnection.java b/src/main/java/com/oneidentity/safeguard/safeguardjava/SafeguardConnection.java index ca12a49..89d9851 100644 --- a/src/main/java/com/oneidentity/safeguard/safeguardjava/SafeguardConnection.java +++ b/src/main/java/com/oneidentity/safeguard/safeguardjava/SafeguardConnection.java @@ -1,5 +1,6 @@ package com.oneidentity.safeguard.safeguardjava; +import com.oneidentity.safeguard.safeguardjava.data.JoinRequest; import com.oneidentity.safeguard.safeguardjava.authentication.AnonymousAuthenticator; import com.oneidentity.safeguard.safeguardjava.authentication.CertificateAuthenticator; import com.oneidentity.safeguard.safeguardjava.authentication.IAuthenticationMechanism; @@ -154,6 +155,26 @@ public String invokeMethodCsv(Service service, Method method, String relativeUrl return invokeMethodFull(service, method, relativeUrl, body, parameters, additionalHeaders, timeout).getBody(); } + + @Override + public FullResponse JoinSps(ISafeguardSessionsConnection spsConnection, String certificateChain, String sppAddress) + throws ObjectDisposedException, SafeguardForJavaException, ArgumentException { + + if (disposed) + throw new ObjectDisposedException("SafeguardConnection"); + + JoinRequest request = new JoinRequest(); + request.setSpp(sppAddress); + request.setSpp_api_token(authenticationMechanism.getAccessToken()); + request.setSpp_cert_chain(certificateChain); + + Logger.getLogger(SafeguardConnection.class.getName()).log(Level.FINEST, "Sending join request."); + FullResponse joinResponse = spsConnection.InvokeMethodFull(Method.Post, "cluster/spp", request.toJson()); + + logResponseDetails(joinResponse); + + return joinResponse; + } @Override public SafeguardEventListener getEventListener() throws ObjectDisposedException, ArgumentException { diff --git a/src/main/java/com/oneidentity/safeguard/safeguardjava/SafeguardForPrivilegedSessions.java b/src/main/java/com/oneidentity/safeguard/safeguardjava/SafeguardForPrivilegedSessions.java new file mode 100644 index 0000000..abe99da --- /dev/null +++ b/src/main/java/com/oneidentity/safeguard/safeguardjava/SafeguardForPrivilegedSessions.java @@ -0,0 +1,34 @@ +package com.oneidentity.safeguard.safeguardjava; + +import com.oneidentity.safeguard.safeguardjava.exceptions.SafeguardForJavaException; + +/** + * This static class provides static methods for connecting to Safeguard for Privileged Sessions API. + */ +public class SafeguardForPrivilegedSessions { + /** + * Connect to Safeguard for Privileged Sessions API using a user name and password. + * + * @param networkAddress Network address of Safeguard for Privileged Sessions appliance. + * @param username User name to use for authentication. + * @param password User password to use for authentication. + * @param ignoreSsl Ignore server certificate validation. + * + * @return Reusable Safeguard for Privileged Sessions API connection. + * @throws SafeguardForJavaException General Safeguard for Java exception. + */ + public static ISafeguardSessionsConnection Connect(String networkAddress, String username, + char[] password, boolean ignoreSsl) + throws SafeguardForJavaException + { + return new SafeguardSessionsConnection(networkAddress, username, password, ignoreSsl, null); + } + + //TODO: This class should provide an Connect API with a validationCallback parameter +// public static ISafeguardSessionsConnection Connect(String networkAddress, String username, +// char[] password, HostnameVerifier validationCallback) +// throws SafeguardForJavaException +// { +// return new SafeguardSessionsConnection(networkAddress, username, password, ignoreSsl); +// } +} diff --git a/src/main/java/com/oneidentity/safeguard/safeguardjava/SafeguardSessionsConnection.java b/src/main/java/com/oneidentity/safeguard/safeguardjava/SafeguardSessionsConnection.java new file mode 100644 index 0000000..07c4473 --- /dev/null +++ b/src/main/java/com/oneidentity/safeguard/safeguardjava/SafeguardSessionsConnection.java @@ -0,0 +1,155 @@ +package com.oneidentity.safeguard.safeguardjava; + +import static com.oneidentity.safeguard.safeguardjava.SafeguardConnection.logRequestDetails; +import static com.oneidentity.safeguard.safeguardjava.SafeguardConnection.logResponseDetails; +import com.oneidentity.safeguard.safeguardjava.data.FullResponse; +import com.oneidentity.safeguard.safeguardjava.data.JsonBody; +import com.oneidentity.safeguard.safeguardjava.data.Method; +import com.oneidentity.safeguard.safeguardjava.exceptions.ArgumentException; +import com.oneidentity.safeguard.safeguardjava.exceptions.ObjectDisposedException; +import com.oneidentity.safeguard.safeguardjava.exceptions.SafeguardForJavaException; +import com.oneidentity.safeguard.safeguardjava.restclient.RestClient; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.net.ssl.HostnameVerifier; +import org.apache.http.Header; +import org.apache.http.HeaderElement; +import org.apache.http.client.methods.CloseableHttpResponse; + +/** + * This is the reusable connection interface that can be used to call SPS API. + */ +class SafeguardSessionsConnection implements ISafeguardSessionsConnection { + + private boolean disposed; + + private RestClient _client; + private Header _authCookie = null; + + public SafeguardSessionsConnection(String networkAddress, String username, + char[] password, boolean ignoreSsl, HostnameVerifier validationCallback) + throws SafeguardForJavaException { + + String spsApiUrl = String.format("https://%s/api", networkAddress); + _client = new RestClient(spsApiUrl, username, password, ignoreSsl, validationCallback); + + Map headers = new HashMap<>(); + + Logger.getLogger(SafeguardSessionsConnection.class.getName()).log(Level.FINEST, "Starting authentication."); + logRequestDetails(Method.Get, _client.getBaseURL() + "/" + "authentication", null, null); + + CloseableHttpResponse response = _client.execGET("authentication", null, null, null); + + if (response == null) { + throw new SafeguardForJavaException(String.format("Unable to authenticate to SPS %s", networkAddress)); + } + + String reply = Utils.getResponse(response); + + if (!Utils.isSuccessful(response.getStatusLine().getStatusCode())) { + throw new SafeguardForJavaException("Error returned from Safeguard API, Error: " + + String.format("%d %s", response.getStatusLine().getStatusCode(), reply)); + } + + Header authCookie = response.getFirstHeader("Set-Cookie"); + if (authCookie != null) { + _client.addSessionId(authCookie.getValue()); + } + + Logger.getLogger(SafeguardSessionsConnection.class.getName()).log(Level.FINEST, String.format("Response content: $s", reply)); + } + + @Override + public String InvokeMethod(Method method, String relativeUrl, String body) + throws ObjectDisposedException, SafeguardForJavaException, ArgumentException { + + return InvokeMethodFull(method, relativeUrl, body).getBody(); + } + + /** + * Call a SafeguardForPrivilegedSessions API method and get a detailed response with status code, headers, + * and body. If there is a failure a SafeguardDotNetException will be thrown. + * + * @param method HTTP method type to use. + * @param relativeUrl The url. + * @param body Request body to pass to the method. + * + * @return Response with status code, headers, and body as string. + */ + @Override + //TODO: This API should have an additionalHeaders parameter + //TODO: This API should have an parameters parameter + //TODO: This API should have an timeout parameter + public FullResponse InvokeMethodFull(Method method, String relativeUrl, String body) + throws ObjectDisposedException, SafeguardForJavaException, ArgumentException { + + if (disposed) { + throw new ObjectDisposedException("SafeguardSessionsConnection"); + } + if (Utils.isNullOrEmpty(relativeUrl)) + throw new ArgumentException("Parameter relativeUrl may not be null or empty"); + + Logger.getLogger(SafeguardSessionsConnection.class.getName()).log(Level.FINEST, String.format("Invoking method on sps: $s", relativeUrl)); + + CloseableHttpResponse response = null; + + logRequestDetails(method, _client.getBaseURL() + "/" + relativeUrl, null, null); + + switch (method) { + case Get: + response = _client.execGET(relativeUrl, null, null, null); + break; + case Post: + response = _client.execPOST(relativeUrl, null, null, null, new JsonBody(body)); + break; + case Put: + response = _client.execPUT(relativeUrl, null, null, null, new JsonBody(body)); + break; + case Delete: + response = _client.execDELETE(relativeUrl, null, null, null); + break; + } + + if (response == null) { + throw new SafeguardForJavaException(String.format("Unable to connect to web service %s", _client.getBaseURL())); + } + + String reply = Utils.getResponse(response); + + if (!Utils.isSuccessful(response.getStatusLine().getStatusCode())) { + throw new SafeguardForJavaException("Error returned from Safeguard API, Error: " + + String.format("%d %s", response.getStatusLine().getStatusCode(), reply)); + } + + Logger.getLogger(SafeguardSessionsConnection.class.getName()).log(Level.FINEST, String.format("Invoking method finished: $s", reply)); + + FullResponse fullResponse = new FullResponse(response.getStatusLine().getStatusCode(), response.getAllHeaders(), reply); + + logResponseDetails(fullResponse); + + return fullResponse; + } + + boolean isDisposed() { + return disposed; + } + + public void dispose() + { + if (_client != null) + _client = null; + disposed = true; + } + + protected void finalize() throws Throwable { + try { + dispose(); + } finally { + disposed = true; + super.finalize(); + } + } + +} diff --git a/src/main/java/com/oneidentity/safeguard/safeguardjava/data/JoinRequest.java b/src/main/java/com/oneidentity/safeguard/safeguardjava/data/JoinRequest.java new file mode 100644 index 0000000..14e80ee --- /dev/null +++ b/src/main/java/com/oneidentity/safeguard/safeguardjava/data/JoinRequest.java @@ -0,0 +1,47 @@ +package com.oneidentity.safeguard.safeguardjava.data; + +import com.oneidentity.safeguard.safeguardjava.Utils; + +public class JoinRequest implements JsonObject { + + private String spp; + private char[] spp_api_token; + private String spp_cert_chain; + + public JoinRequest() { + } + + public String getSpp() { + return spp; + } + + public void setSpp(String spp) { + this.spp = spp; + } + + public char[] getSpp_api_token() { + return spp_api_token; + } + + public void setSpp_api_token(char[] spp_api_token) { + this.spp_api_token = spp_api_token; + } + + public String getSpp_cert_chain() { + return spp_cert_chain; + } + + public void setSpp_cert_chain(String spp_cert_chain) { + this.spp_cert_chain = spp_cert_chain; + } + + @Override + public String toJson() { + return new StringBuffer("{") + .append(Utils.toJsonString("spp", this.spp, false)) + .append(Utils.toJsonString("spp_api_token", this.spp_api_token.toString(), true)) + .append(Utils.toJsonString("spp_cert_chain", this.spp_cert_chain, true)) + .append("}").toString(); + } + +} diff --git a/src/main/java/com/oneidentity/safeguard/safeguardjava/restclient/RestClient.java b/src/main/java/com/oneidentity/safeguard/safeguardjava/restclient/RestClient.java index 5dd948a..9e93f50 100644 --- a/src/main/java/com/oneidentity/safeguard/safeguardjava/restclient/RestClient.java +++ b/src/main/java/com/oneidentity/safeguard/safeguardjava/restclient/RestClient.java @@ -20,8 +20,10 @@ import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -39,6 +41,9 @@ import javax.net.ssl.X509KeyManager; import javax.net.ssl.X509TrustManager; import org.apache.http.HttpHeaders; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.RequestBuilder; @@ -47,14 +52,22 @@ import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.cookie.Cookie; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.BasicHttpClientConnectionManager; import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.BasicCookieStore; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.cookie.BasicClientCookie; public class RestClient { private CloseableHttpClient client = null; + private HttpClientBuilder builder = null; + private BasicCookieStore cookieStore = new BasicCookieStore(); + private String serverUrl = null; private boolean ignoreSsl = false; private HostnameVerifier validationCallback = null; @@ -63,6 +76,22 @@ public class RestClient { public RestClient(String connectionAddr, boolean ignoreSsl, HostnameVerifier validationCallback) { + client = createClientBuilder(connectionAddr, ignoreSsl, validationCallback).build(); + } + + public RestClient(String connectionAddr, String userName, char[] password, boolean ignoreSsl, HostnameVerifier validationCallback) { + + + HttpClientBuilder builder = createClientBuilder(connectionAddr, ignoreSsl, validationCallback); + CredentialsProvider provider = new BasicCredentialsProvider(); + provider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(userName, new String(password))); + + client = builder.setDefaultCredentialsProvider(provider).setDefaultCookieStore(cookieStore).disableCookieManagement().build(); + } + + private HttpClientBuilder createClientBuilder(String connectionAddr, boolean ignoreSsl, HostnameVerifier validationCallback) { + + // Used to produce debug output if (false) { Handler handlerObj = new ConsoleHandler(); handlerObj.setLevel(Level.ALL); @@ -86,10 +115,10 @@ public RestClient(String connectionAddr, boolean ignoreSsl, HostnameVerifier val } Registry socketFactoryRegistry = RegistryBuilder. create().register("https", sslsf).build(); BasicHttpClientConnectionManager connectionManager = new BasicHttpClientConnectionManager(socketFactoryRegistry); - client = HttpClients.custom().setSSLSocketFactory(sslsf).setConnectionManager(connectionManager).build(); - + + return HttpClients.custom().setSSLSocketFactory(sslsf).setConnectionManager(connectionManager); } - + private URI getBaseURI(String segments) { try { return new URI(serverUrl+"/"+segments); @@ -103,6 +132,61 @@ public String getBaseURL() { return serverUrl; } + private Map parseKeyValue(String value) { + + HashMap keyValues = new HashMap(); + String[] parts = value.split(";"); + for (String p : parts) { + String[] kv = p.split("="); + if (kv.length == 1) { + keyValues.put(kv[0].trim(), ""); + } + if (kv.length == 2) { + keyValues.put(kv[0].trim(), kv[1].trim()); + } + } + + return keyValues; + } + + public void addSessionId(String cookieValue) { + if (cookieValue == null) { + Logger.getLogger(RestClient.class.getName()).log(Level.SEVERE, "Session cookie cannot be null"); + return; + } + + try { + Map keyValues = parseKeyValue(cookieValue); + + String sessionId = keyValues.get("session_id"); + if (sessionId != null) { + BasicClientCookie cookie = new BasicClientCookie("session_id", sessionId); + + String expiryDate = keyValues.get("expires"); + if (expiryDate != null) { + SimpleDateFormat formatter = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z"); + Date date = formatter.parse(expiryDate); + cookie.setExpiryDate(date); + } + + String path = keyValues.get("Path"); + if (path != null) { + cookie.setPath(path); + } + + String secure = keyValues.get("Secure"); + if (secure != null) { + cookie.setSecure(true); + } + + this.cookieStore.addCookie(cookie); + } + } + catch (Exception ex) { + Logger.getLogger(RestClient.class.getName()).log(Level.SEVERE, "Failed to set session cookie.", ex); + } + } + public CloseableHttpResponse execGET(String path, Map queryParams, Map headers, Integer timeout) { RequestBuilder rb = prepareRequest (RequestBuilder.get(getBaseURI(path)), queryParams, headers, timeout); diff --git a/tests/safeguardjavaclient/pom.xml b/tests/safeguardjavaclient/pom.xml index 1f78017..349c5c2 100644 --- a/tests/safeguardjavaclient/pom.xml +++ b/tests/safeguardjavaclient/pom.xml @@ -23,7 +23,7 @@ com.oneidentity.safeguard safeguardjava - 6.10.0-SNAPSHOT + 6.11.0-SNAPSHOT diff --git a/tests/safeguardjavaclient/src/main/java/com/oneidentity/safeguard/safeguardclient/SafeguardJavaClient.java b/tests/safeguardjavaclient/src/main/java/com/oneidentity/safeguard/safeguardclient/SafeguardJavaClient.java index 6e57b0e..be15c42 100644 --- a/tests/safeguardjavaclient/src/main/java/com/oneidentity/safeguard/safeguardclient/SafeguardJavaClient.java +++ b/tests/safeguardjavaclient/src/main/java/com/oneidentity/safeguard/safeguardclient/SafeguardJavaClient.java @@ -2,6 +2,7 @@ import com.oneidentity.safeguard.safeguardjava.ISafeguardA2AContext; import com.oneidentity.safeguard.safeguardjava.ISafeguardConnection; +import com.oneidentity.safeguard.safeguardjava.ISafeguardSessionsConnection; import com.oneidentity.safeguard.safeguardjava.event.ISafeguardEventListener; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; @@ -19,6 +20,7 @@ public class SafeguardJavaClient { public static void main(String[] args) { ISafeguardConnection connection = null; + ISafeguardSessionsConnection sessionConnection = null; ISafeguardA2AContext a2aContext = null; ISafeguardEventListener eventListener = null; @@ -92,6 +94,12 @@ public static void main(String[] args) { case 21: tests.safeguardTestBackupUpload(connection); break; + case 22: + sessionConnection = tests.safeguardSessionsConnection(); + break; + case 23: + tests.safeguardSessionsApi(sessionConnection); + break; default: done = true; break; @@ -125,6 +133,8 @@ private static Integer displayMenu() { System.out.println ("\t19. Disconnect Event Listener"); System.out.println ("\t20. Test Download Backup File"); System.out.println ("\t21. Test Upload Backup File"); + System.out.println ("\t22. Test SPS Connection"); + System.out.println ("\t23. Test SPS API"); System.out.println ("\t99. Exit"); diff --git a/tests/safeguardjavaclient/src/main/java/com/oneidentity/safeguard/safeguardclient/SafeguardTests.java b/tests/safeguardjavaclient/src/main/java/com/oneidentity/safeguard/safeguardclient/SafeguardTests.java index 0a0959f..6f3573f 100644 --- a/tests/safeguardjavaclient/src/main/java/com/oneidentity/safeguard/safeguardclient/SafeguardTests.java +++ b/tests/safeguardjavaclient/src/main/java/com/oneidentity/safeguard/safeguardclient/SafeguardTests.java @@ -4,7 +4,9 @@ import com.oneidentity.safeguard.safeguardjava.IProgressCallback; import com.oneidentity.safeguard.safeguardjava.ISafeguardA2AContext; import com.oneidentity.safeguard.safeguardjava.ISafeguardConnection; +import com.oneidentity.safeguard.safeguardjava.ISafeguardSessionsConnection; import com.oneidentity.safeguard.safeguardjava.Safeguard; +import com.oneidentity.safeguard.safeguardjava.SafeguardForPrivilegedSessions; import com.oneidentity.safeguard.safeguardjava.data.A2ARetrievableAccount; import com.oneidentity.safeguard.safeguardjava.data.BrokeredAccessRequest; import com.oneidentity.safeguard.safeguardjava.data.FullResponse; @@ -548,5 +550,49 @@ public void safeguardTestBackupUpload(ISafeguardConnection connection) { System.out.println("\t[ERROR]Test backup download failed: " + ex.getMessage()); } } + + ISafeguardSessionsConnection safeguardSessionsConnection() { + String address = readLine("SPP address: ", null); + String user = readLine("User:", null); + String password = readLine("Password: ", null); +// boolean withCertValidator = readLine("With Certificate Validator(y/n): ", "n").equalsIgnoreCase("y"); + boolean ignoreSsl = readLine("Ignore SSL(y/n): ", "y").equalsIgnoreCase("y"); + + ISafeguardSessionsConnection connection = null; + + try { +// if (withCertValidator) { +// connection = Safeguard.connect(address, provider, user, password.toCharArray(), new CertificateValidator(), null); +// } else { + connection = SafeguardForPrivilegedSessions.Connect(address, user, password.toCharArray(), true); +// } + } catch (SafeguardForJavaException ex) { + System.out.println("\t[ERROR]Connection failed: " + ex.getMessage()); + } catch (Exception ex) { + System.out.println("\t[ERROR]Connection failed: " + ex.getMessage()); + } + + if (connection != null) + System.out.println("\tSuccessful connection."); + return connection; + } + + void safeguardSessionsApi(ISafeguardSessionsConnection connection) { + if (connection == null) { + System.out.println(String.format("Safeguard sessions not connected")); + return; + } + + try { + FullResponse fullResponse = connection.InvokeMethodFull(Method.Get, "firmware", null); + System.out.println(String.format("\t\\Users full response:")); + System.out.println(fullResponse.getBody()); + + } catch (ObjectDisposedException | SafeguardForJavaException ex) { + System.out.println("\t[ERROR]Test connection failed: " + ex.getMessage()); + } catch (Exception ex) { + System.out.println("\t[ERROR]Test connection failed: " + ex.getMessage()); + } + } }