diff --git a/.swagger-codegen/VERSION b/.swagger-codegen/VERSION index 580ce10..19244e8 100644 --- a/.swagger-codegen/VERSION +++ b/.swagger-codegen/VERSION @@ -1 +1 @@ -2.4.21-SNAPSHOT \ No newline at end of file +2.4.21 \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d9e67e..357e887 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # DocuSign Monitor Java Client Changelog See [DocuSign Support Center](https://support.docusign.com/en/releasenotes/) for Product Release Notes. +## [v2.0.0] - Monitor API v2.0-3.0.1 - 2026-07-29 +### Changed +- Added support for version v2.0-3.0.1 of the DocuSign Monitor API. +- Updated the SDK release version. + ## [v1.4.0] - Monitor API v2.0-2.0.0 - 2023-06-14 ### Changed - Added support for version v2.0-2.0.0 of the DocuSign Monitor API. diff --git a/README.md b/README.md index 0c63483..df7b1cb 100644 --- a/README.md +++ b/README.md @@ -1,88 +1,167 @@ -# The Official DocuSign Monitor Java Client +# The Official Docusign Monitor Java Client SDK [![Build status][travis-image]][travis-url] [![Maven Central status][maven-image]][maven-url] -## Requirements +The Docusign SDK makes integrating Docusign into your apps and websites a seamless experience. + +## Table of Contents +- [Introduction](#introduction) +- [Installation](#installation) + * [Version Information](#versionInformation) + * [Requirements](#requirements) + * [Compatibility](#compatibility) + * [Maven](#maven) +- [Dependencies](#dependencies) +- [API Reference](#apiReference) +- [Code Examples](#codeExamples) +- [OAuth Implementations](#oauthImplementations) +- [Security](#security) +- [Changelog](#changeLog) +- [Support](#support) +- [License](#license) +- [Additional Resources](#additionalResources) + + +## Introduction +Docusign Monitor helps organizations protect their agreements with round-the-clock activity tracking. The Monitor API delivers this activity tracking information directly to existing security stacks or data visualization tools—enabling teams to detect unauthorized activity, investigate incidents, and quickly respond to verified threats. It also provides the flexibility security teams need to customize dashboards and alerts to meet specific business needs. + + +## Installation +This client SDK is provided as open source, which enables you to customize its functionality to suit your particular use case. To do so, download or clone the repository. If the SDK’s given functionality meets your integration needs, or if you’re working through our [code examples](https://developers.docusign.com/docs/monitor-api/how-to/) from the [Docusign Developer Center](https://developers.docusign.com/), you merely need to install it by following the instructions below. -- Java 1.9+ -- Free [Developer Sandbox](https://go.docusign.com/sandbox/productshot/?elqCampaignId=16531) + +### Version Information +- **API version**: v3.0 +- **Latest SDK version (Including prerelease)**: + + +## Requirements +* Java 1.9+ +* Free [developer account](https://go.docusign.com/o/sandbox/?postActivateUrl=https://developers.docusign.com/) + ## Compatibility +* Java 1.9+ -- Java 1.9+ + +**Note:** Docusign uses Eclipse with Maven for testing purposes. +### Maven: +1. In Eclipse, create a new project by selecting **File > New > Project**. +2. In the New Project Wizard, expand **Maven,** then select **Maven Project.** +3. Leave **Create a simple project** unchecked. +4. Select **Next,** then provide a unique **groupId** and **artifactId.** +5. In the directory where you've saved your project, open the pom.xml file. +6. In the pom.xml file, locate the `dependencies` node. +7. Add: + ``` + + com.docusign + docusign-monitor-java + 2.0.0 + + ``` +8. If your project is still open, restart Eclipse. + + +## SDK Dependencies +This client has the following external dependencies: +* io.swagger.core.v3:swagger-annotations:2.2.8 +* org.glassfish.jersey.core:jersey-client:3.1.6 +* org.glassfish.jersey.media:jersey-media-multipart:3.1.6 +* org.glassfish.jersey.media:jersey-media-json-jackson:3.1.6 +* org.glassfish.jersey.inject:jersey-hk2:3.1.6 +* com.fasterxml.jackson.jakarta.rs:jackson-jakarta-rs-base:2.14.2 +* com.auth0:java-jwt:3.4.1 +* org.bouncycastle:bcprov-jdk18on:1.78.1 +* com.fasterxml.jackson.dataformat:jackson-dataformat-csv:2.14.2 +* com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.14.2 +* com.brsanthu:migbase64:2.2 +* com.fasterxml.jackson.core:jackson-core:2.17.1 +* org.json:json:20240303 -## Note -This open-source SDK is provided for cases where you would like to make additional changes that the SDK does not - provide out-of-the-box. If you simply want to use the SDK with any of the examples shown in the [Developer Center ](https://developers.docusign.com/monitor-api/code-examples), follow the installation instructions below. + +## API Reference +You can refer to the API reference [here](https://developers.docusign.com/docs/monitor-api/reference/). -## Installation + +## Code examples +Explore our GitHub repository for the [Launcher](https://github.com/docusign/code-examples-java/), a self-executing package housing code examples for the Monitor Java SDK. This package showcases several common use cases and their respective source files. Additionally, you can download a version preconfigured for your Docusign developer account from [Quickstart](https://developers.docusign.com/docs/esign-rest-api/quickstart/). These examples support both the [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) and [JSON Web Token (JWT)](https://developers.docusign.com/platform/auth/jwt/) authentication workflows. -Note: DocuSign uses **Eclipse** with **Maven** for testing purposes. + +## OAuth implementations +For details regarding which type of OAuth grant will work best for your Docusign integration, see [Choose OAuth Type](https://developers.docusign.com/platform/auth/choose/) in the [Docusign Developer Center](https://developers.docusign.com/). -### Maven: +For security purposes, Docusign recommends using the [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) flow. -1. In Eclipse, create a new project by selecting **File** -> **New** -> **Project**. -2. In the **New Project Wizard** , expand **Maven** , then select **Maven Project.** -3. Leave **Create a simple project** unchecked. -4. Select **Next** , then provide a unique **Group** and **Artifact Id**. -5. In the directory where you've saved your project, open the _pom.xml_ file. -6. In the _pom.xml_ file, locate the **dependencies** node. -7. Add: + +## Security -``` - - com.docusign - docusign-monitor-java - 1.1.0 - -``` +This SDK enforces secure-by-default transport behavior: -8. If your project is still open, restart **Eclipse**. +* **TLS certificate validation** is enforced by default using the system's trust store and default `HostnameVerifier`. +* **HTTPS-only base paths** — `setBasePath()` and the `ApiClient(String basePath)` constructor reject `http://` URLs by default. +* **OAuth base path validation** — `setOAuthBasePath()` also enforces HTTPS. +* **TLS 1.2 required** — The SDK fails fast if TLSv1.2 is not available on the JVM. -## Dependencies +### Testing with self-signed certificates or HTTP endpoints -This client has the following external dependencies: +For local development or testing scenarios that require HTTP or self-signed certificates, use the explicit `ApiClient.insecure()` factory: -- io.swagger:swagger-annotations:jar:1.5.17 -- org.glassfish.jersey.core:jersey-client:jar:2.29.1 -- org.glassfish.jersey.media:jersey-media-multipart:jar:2.29.1 -- org.glassfish.jersey.media:jersey-media-json-jackson:2.29.1 -- com.fasterxml.jackson.core:jackson-core:jar:2.10.1 -- com.fasterxml.jackson.core:jackson-annotations:jar:2.10.1 -- com.fasterxml.jackson.core:jackson-databind:2.10.1 -- com.fasterxml.jackson.datatype:jackson-datatype-joda:jar:2.10.1 -- com.brsanthu:migbase64:2.2 -- junit:junit:jar:4.12 -- com.apache.oltu.oauth2:org.apache.oltu.oauth2.client:1.0.2 -- com.auth0:java-jwt:3.4.1 -- org.bouncycastle:bcprov-jdk15on:1.60 +```java +// HTTP endpoint for local testing +ApiClient client = ApiClient.insecure("http://localhost:8080/restapi"); -## OAuth Implementations +// Self-signed certificate +ApiClient client = ApiClient.insecure("https://dev-server.local/restapi"); -For details regarding which type of OAuth grant will work best for your DocuSign integration, see the [REST API - Authentication Overview](https://developers.docusign.com/monitor-api/guides/auth) guide located on the [DocuSign Developer Center](https://developers.docusign.com/). +// Insecure client with default base path +ApiClient client = ApiClient.insecure(); +client.setBasePath("http://localhost:8080/restapi"); +``` -For security purposes, DocuSign recommends using the Authorization Code Grant flow. +> **Warning:** `ApiClient.insecure()` disables TLS certificate validation and hostname verification. Never use in production. -## Support +### Proxy authentication -Log issues against this client through GitHub. We also have an [active developer community on Stack Overflow](https://stackoverflow.com/questions/tagged/docusignapi). +By default, when proxy credentials are set via system properties (`https.proxyUser` / `https.proxyPassword`), the SDK configures a JVM-wide `Authenticator` scoped to the proxy host and port. This preserves backward compatibility with existing enterprise configurations. -## License +If you prefer per-connection proxy authentication (which avoids JVM-global side effects), enable it via the setter before the first request: -The DocuSign Java Client is licensed under the [MIT License](https://github.com/docusign/docusign-monitor-java-client/blob -/master/LICENSE). +```java +ApiClient client = new ApiClient(); +client.setPerConnectionProxyAuth(true); +``` +Or use the convenience constructor: -[travis-image]: https://img.shields.io/travis/docusign/docusign-monitor-java-client.svg?style=flat -[travis-url]: https://travis-ci.org/docusign/docusign-monitor-java-client -[maven-image]: https://img.shields.io/maven-central/v/com.docusign/docusign-monitor-java.svg?style=flat -[maven-url]: https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.docusign%22 +```java +ApiClient client = new ApiClient(true); +``` -### Additional Resources -* [DocuSign Developer Center](https://developers.docusign.com) -* [DocuSign API on Twitter](https://twitter.com/docusignapi) -* [DocuSign For Developers on LinkedIn](https://www.linkedin.com/showcase/docusign-for-developers/) -* [DocuSign For Developers on YouTube](https://www.youtube.com/channel/UCJSJ2kMs_qeQotmw4-lX2NQ) +> **Note:** Per-connection proxy auth will become the default in a future major version. + + +## Changelog +You can refer to the complete changelog [here](https://github.com/docusign/docusign-monitor-java-client/blob/master/CHANGELOG.md). + + +## Support +Log issues against this client SDK through GitHub. You can also reach out to us through [Docusign Community](https://community.docusign.com/developer-59) and [Stack Overflow](https://stackoverflow.com/questions/tagged/docusignapi). + + +## License +The Docusign Monitor Java Client SDK is licensed under the [MIT License](https://github.com/docusign/docusign-monitor-java-client/blob/master/LICENSE). + + +### Additional resources +* [Docusign Developer Center](https://developers.docusign.com/) +* [Docusign API on Twitter](https://twitter.com/docusignapi) +* [Docusign For Developers on LinkedIn](https://www.linkedin.com/showcase/docusign-for-developers/) +* [Docusign For Developers on YouTube](https://www.youtube.com/channel/UCJSJ2kMs_qeQotmw4-lX2NQ) + +[travis-image]: https://api.travis-ci.com/docusign/docusign-monitor-java-client.svg?branch=master +[travis-url]: https://app.travis-ci.com/github/docusign/docusign-monitor-java-client +[maven-image]: https://img.shields.io/maven-central/v/com.docusign/.svg?style=flat +[maven-url]: https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.docusign%22 diff --git a/pom.xml b/pom.xml index d400f8c..76d9621 100644 --- a/pom.xml +++ b/pom.xml @@ -5,9 +5,9 @@ docusign-monitor-java jar docusign-monitor-java - 1.4.0 + 2.0.0 https://developers.docusign.com - The official DocuSign Monitor Java client provides libraries for Java application integration with DocuSign Monitor for real estate and mortgage workflows. It is recommended that you use this version of the library for new development. + The official Docusign Monitor Java client provides libraries for Java application integration with Docusign Monitor for real estate and mortgage workflows. It is recommended that you use this version of the library for new development. 2.2.0 @@ -15,12 +15,12 @@ - ossrh - https://s01.oss.sonatype.org/content/repositories/snapshots + central + https://central.sonatype.com/repository/maven-snapshots/ - ossrh2 - https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ + central + https://central.sonatype.com/repository/maven-releases/ @@ -33,7 +33,7 @@ DocuSign Monitor Java Client License - https://raw.githubusercontent.com/docusign/docusign-monitor-java-client/master/LICENSE + https://www.docusign.com/company/terms-and-conditions/web repo @@ -52,7 +52,7 @@ com.diffplug.spotless spotless-maven-plugin - 2.12.1 + 2.43.0 @@ -66,7 +66,7 @@ - 1.7 + 1.21.0 @@ -227,6 +227,21 @@ + + org.owasp + dependency-check-maven + 12.1.1 + + 8 + + + + + check + + + + org.apache.maven.plugins maven-source-plugin @@ -294,13 +309,13 @@ - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.8 + org.sonatype.central + central-publishing-maven-plugin + 0.8.0 + true - ossrh - https://s01.oss.sonatype.org/ - true + central + true @@ -329,6 +344,7 @@ jersey-media-json-jackson ${jersey-version} + org.glassfish.jersey.inject jersey-hk2 @@ -340,11 +356,6 @@ jackson-jakarta-rs-base ${jackson-version} - - org.apache.oltu.oauth2 - org.apache.oltu.oauth2.client - ${oltu-version} - com.auth0 @@ -353,8 +364,8 @@ org.bouncycastle - bcprov-jdk15on - 1.69 + bcprov-jdk18on + 1.78.1 com.fasterxml.jackson.dataformat @@ -390,13 +401,28 @@ migbase64 2.2 + + org.junit.jupiter + junit-jupiter-api + 5.10.2 + test + + + com.fasterxml.jackson.core + jackson-core + 2.17.1 + + + org.json + json + 20240303 + UTF-8 2.2.8 - 3.0.9 + 3.1.6 2.14.2 4.13.1 - 1.0.2 diff --git a/src/main/java/com/docusign/monitor/api/DocuMonitorApi.java b/src/main/java/com/docusign/monitor/api/DocuMonitorApi.java new file mode 100644 index 0000000..e768779 --- /dev/null +++ b/src/main/java/com/docusign/monitor/api/DocuMonitorApi.java @@ -0,0 +1,177 @@ + +package com.docusign.monitor.api; + +import jakarta.ws.rs.core.GenericType; + +import com.docusign.monitor.client.ApiException; +import com.docusign.monitor.client.ApiClient; +import com.docusign.monitor.client.Configuration; +import com.docusign.monitor.model.*; +import com.docusign.monitor.client.Pair; +import com.docusign.monitor.client.ApiResponse; + + + + +/** + * DocuMonitorApi class. + * + **/ +public class DocuMonitorApi { + private ApiClient apiClient; + + /** + * DocuMonitorApi. + * + **/ + public DocuMonitorApi() { + this(Configuration.getDefaultApiClient()); + } + + /** + * DocuMonitorApi. + * + **/ + public DocuMonitorApi(ApiClient apiClient) { + this.apiClient = apiClient; + } + + /** + * getApiClient Method. + * + * @return ApiClient + **/ + public ApiClient getApiClient() { + return apiClient; + } + + /** + * setApiClient Method. + * + **/ + public void setApiClient(ApiClient apiClient) { + this.apiClient = apiClient; + } + + /// + /// Gets customer event data for an organization. Gets customer event data for the organization that owns the integration key. The results for this endpoint are paginated by their event ingestion time, which can be up to five minutes after the event originally occurred. Use the `cursor` parameter to specify where the query begins in the dataset. Use the `limit` parameter to set the number of records returned. For a detailed example of how to use `getStream` and retrieve monitoring data, see our guides [How to get monitoring data](/docs/monitor-api/how-to/get-monitoring-data/) and [Tracking data and handling alerts](/docs/monitor-api/monitor101/tracking-data-handling-alerts/). **Note**: data is not guaranteed to be in the order of the timestamp of the events. It is returned in the order it was inserted into our database. ### Related topics - [How to get monitoring data](/docs/monitor-api/how-to/get-monitoring-data/) - [Tracking data and handling alerts](/docs/monitor-api/monitor101/tracking-data-handling-alerts/) + /// + + /** + * StreamOptions Class. + * + **/ + public class StreamOptions + { + private String cursor = null; + private Integer limit = null; + + /** + * setCursor method. + */ + public void setCursor(String cursor) { + this.cursor = cursor; + } + + /** + * getCursor method. + * + * @return String + */ + public String getCursor() { + return this.cursor; + } + + /** + * setLimit method. + */ + public void setLimit(Integer limit) { + this.limit = limit; + } + + /** + * getLimit method. + * + * @return Integer + */ + public Integer getLimit() { + return this.limit; + } + } + + /** + * Gets customer event data for an organization.. + * Gets customer event data for the organization that owns the integration key. The results for this endpoint are paginated by their event ingestion time, which can be up to five minutes after the event originally occurred. Use the `cursor` parameter to specify where the query begins in the dataset. Use the `limit` parameter to set the number of records returned. For a detailed example of how to use `getStream` and retrieve monitoring data, see our guides [How to get monitoring data](/docs/monitor-api/how-to/get-monitoring-data/) and [Tracking data and handling alerts](/docs/monitor-api/monitor101/tracking-data-handling-alerts/). **Note**: data is not guaranteed to be in the order of the timestamp of the events. It is returned in the order it was inserted into our database. ### Related topics - [How to get monitoring data](/docs/monitor-api/how-to/get-monitoring-data/) - [Tracking data and handling alerts](/docs/monitor-api/monitor101/tracking-data-handling-alerts/) + * @param organizationId (required) + * @return StreamResponse + */ + public StreamResponse stream(java.util.UUID organizationId) throws ApiException { + return stream(organizationId, null); + } + + /** + * Gets customer event data for an organization.. + * Gets customer event data for the organization that owns the integration key. The results for this endpoint are paginated by their event ingestion time, which can be up to five minutes after the event originally occurred. Use the `cursor` parameter to specify where the query begins in the dataset. Use the `limit` parameter to set the number of records returned. For a detailed example of how to use `getStream` and retrieve monitoring data, see our guides [How to get monitoring data](/docs/monitor-api/how-to/get-monitoring-data/) and [Tracking data and handling alerts](/docs/monitor-api/monitor101/tracking-data-handling-alerts/). **Note**: data is not guaranteed to be in the order of the timestamp of the events. It is returned in the order it was inserted into our database. ### Related topics - [How to get monitoring data](/docs/monitor-api/how-to/get-monitoring-data/) - [Tracking data and handling alerts](/docs/monitor-api/monitor101/tracking-data-handling-alerts/) + * @param organizationId (required) + * @param options for modifying the method behavior. + * @return StreamResponse + * @throws ApiException if fails to make API call + */ + public StreamResponse stream(java.util.UUID organizationId, DocuMonitorApi.StreamOptions options) throws ApiException { + ApiResponse localVarResponse = streamWithHttpInfo(organizationId, options); + return localVarResponse.getData(); + } + + /** + * Gets customer event data for an organization. + * Gets customer event data for the organization that owns the integration key. The results for this endpoint are paginated by their event ingestion time, which can be up to five minutes after the event originally occurred. Use the `cursor` parameter to specify where the query begins in the dataset. Use the `limit` parameter to set the number of records returned. For a detailed example of how to use `getStream` and retrieve monitoring data, see our guides [How to get monitoring data](/docs/monitor-api/how-to/get-monitoring-data/) and [Tracking data and handling alerts](/docs/monitor-api/monitor101/tracking-data-handling-alerts/). **Note**: data is not guaranteed to be in the order of the timestamp of the events. It is returned in the order it was inserted into our database. ### Related topics - [How to get monitoring data](/docs/monitor-api/how-to/get-monitoring-data/) - [Tracking data and handling alerts](/docs/monitor-api/monitor101/tracking-data-handling-alerts/) + * @param organizationId (required) + * @param options for modifying the method behavior. + * @return StreamResponse + * @throws ApiException if fails to make API call + */ + public ApiResponse streamWithHttpInfo(java.util.UUID organizationId, DocuMonitorApi.StreamOptions options) throws ApiException { + Object localVarPostBody = "{}"; + + // verify the required parameter 'organizationId' is set + if (organizationId == null) { + throw new ApiException(400, "Missing the required parameter 'organizationId' when calling stream"); + } + + // create path and map variables + String localVarPath = "/v1/organizations/{organizationId}/stream" + .replaceAll("\\{" + "organizationId" + "\\}", apiClient.escapeString(organizationId.toString())); + + // query params + java.util.List localVarQueryParams = new java.util.ArrayList(); + java.util.List localVarCollectionQueryParams = new java.util.ArrayList(); + java.util.Map localVarHeaderParams = new java.util.HashMap(); + java.util.Map localVarFormParams = new java.util.HashMap(); + + if (options != null) { + localVarQueryParams.addAll(apiClient.parameterToPair("cursor", options.cursor)); + }if (options != null) { + localVarQueryParams.addAll(apiClient.parameterToPair("limit", options.limit)); + } + + + + + + final String[] localVarAccepts = { + "application/json" + }; + final String localVarAccept = apiClient.selectHeaderAccept(localVarAccepts); + + final String[] localVarContentTypes = { + "application/json" + }; + final String localVarContentType = apiClient.selectHeaderContentType(localVarContentTypes); + + String[] localVarAuthNames = new String[] { "docusignAccessCode" }; + + GenericType localVarReturnType = new GenericType() {}; + StreamResponse localVarResponse = apiClient.invokeAPI(localVarPath, "GET", localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarFormParams, localVarAccept, localVarContentType, localVarAuthNames, localVarReturnType); + return new ApiResponse(apiClient.getStatusCode(), apiClient.getResponseHeaders(), localVarResponse); + } +} diff --git a/src/main/java/com/docusign/monitor/client/ApiClient.java b/src/main/java/com/docusign/monitor/client/ApiClient.java index acf535e..bea36fc 100644 --- a/src/main/java/com/docusign/monitor/client/ApiClient.java +++ b/src/main/java/com/docusign/monitor/client/ApiClient.java @@ -9,10 +9,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.csv.CsvMapper; import com.fasterxml.jackson.dataformat.csv.CsvSchema; -import com.migcomponents.migbase64.Base64; -import org.apache.oltu.oauth2.client.request.OAuthClientRequest.AuthenticationRequestBuilder; -import org.apache.oltu.oauth2.client.request.OAuthClientRequest.TokenRequestBuilder; -import org.apache.oltu.oauth2.common.exception.OAuthSystemException; import org.glassfish.jersey.client.ClientConfig; import org.glassfish.jersey.client.ClientProperties; import org.glassfish.jersey.client.HttpUrlConnectorProvider; @@ -34,14 +30,19 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.*; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.StandardCopyOption; import org.glassfish.jersey.logging.LoggingFeature; +import java.security.KeyStore; import java.security.SecureRandom; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.security.NoSuchAlgorithmException; +import javax.net.ssl.TrustManagerFactory; +import java.util.Arrays; +import java.util.logging.Logger; import java.text.DateFormat; import java.util.*; import java.util.Map.Entry; @@ -57,16 +58,16 @@ **/ public class ApiClient { + private static final Logger logger = Logger.getLogger(ApiClient.class.getName()); + protected Map defaultHeaderMap = new HashMap(); // Rest API base path constants /** live/production base path. */ public final static String PRODUCTION_REST_BASEPATH = "https://www.docusign.net/restapi"; /** sandbox/demo base path. */ public final static String DEMO_REST_BASEPATH = "https://demo.docusign.net/restapi"; - /** stage base path. */ - public final static String STAGE_REST_BASEPATH = "https://stage.docusign.net/restapi"; - private String basePath = PRODUCTION_REST_BASEPATH; + private String basePath = DEMO_REST_BASEPATH; private String oAuthBasePath = OAuth.PRODUCTION_OAUTH_BASEPATH; protected boolean debugging = false; protected int connectionTimeout = 0; @@ -84,11 +85,32 @@ public class ApiClient { protected DateFormat dateFormat; private SSLContext sslContext = null; - /** - * ApiClient constructor. - * - **/ - public ApiClient() { + private final String HTTPS = "https://"; + + /** + * When false (the default), the SDK uses the system's default TrustManager and + * HostnameVerifier for secure HTTPS connections and enforces HTTPS-only base paths. + * When true, allows insecure connections: trusts all certificates, skips hostname + * verification, and allows HTTP base paths. Only enable for testing purposes. + */ + private boolean allowInsecureConnections = false; + + /** + * When true, proxy credentials from system properties are applied per-connection + * using the Proxy-Authorization header instead of the JVM-wide Authenticator.setDefault(). + * This avoids leaking credentials to unrelated HTTP clients in the same JVM. + * Default is false (JVM-wide Authenticator) for backward compatibility. + */ + private boolean perConnectionProxyAuth = false; + + private ApiClient(String basePath, boolean allowInsecureConnections, boolean perConnectionProxyAuth) { + this.allowInsecureConnections = allowInsecureConnections; + this.perConnectionProxyAuth = perConnectionProxyAuth; + if (basePath != null) { + validateBasePath(basePath); + this.basePath = basePath; + } + json = new JSON(); httpClient = buildHttpClient(debugging); @@ -96,16 +118,33 @@ public ApiClient() { String javaVersion = System.getProperty("java.version"); // Set default User-Agent. - setUserAgent("/SDK/1.4.0/Java/"); + setUserAgent("Swagger-Codegen/v3.0/2.0.0/Java/" + javaVersion); // Setup authentications (key: authentication name, value: authentication). authentications = new HashMap(); - authentications.put("docusignAccessCode", new OAuth()); + authentications.put("docusignAccessCode", new OAuth(httpClient)); - // Derive the OAuth base path from the Rest API base url this.deriveOAuthBasePathFromRestBasePath(); } + /** + * ApiClient constructor. + * + **/ + public ApiClient() { + this(null, false, false); + } + + /** + * ApiClient constructor. + * + * @param perConnectionProxyAuth true to use per-connection proxy authentication + * from construction time instead of the JVM-wide Authenticator + **/ + public ApiClient(boolean perConnectionProxyAuth) { + this(null, false, perConnectionProxyAuth); + } + /** * buildDefaultDateFormat method. * @@ -118,12 +157,11 @@ public static DateFormat buildDefaultDateFormat() { /** * ApiClient constructor. * - * @param basePath The base path to create the client with + * @param basePath The base path to create the client with. Must use HTTPS. + * @throws IllegalArgumentException if basePath uses HTTP **/ public ApiClient(String basePath) { - this(); - this.basePath = basePath; - this.deriveOAuthBasePathFromRestBasePath(); + this(basePath, false, false); } /** @@ -133,12 +171,12 @@ public ApiClient(String basePath) { * @param authNames The authentication names **/ public ApiClient(String oAuthBasePath, String[] authNames) { - this(); + this(null, false, false); this.setOAuthBasePath(oAuthBasePath); for(String authName : authNames) { Authentication auth; if ("docusignAccessCode".equals(authName)) { - auth = new OAuth(httpClient, OAuthFlow.accessCode, oAuthBasePath + "/oauth/auth", oAuthBasePath + "/oauth/token", "all"); + auth = new OAuth(httpClient, OAuthFlow.accessCode, HTTPS + oAuthBasePath + "/oauth/auth", HTTPS + oAuthBasePath + "/oauth/token", "all"); } else if ("docusignApiKey".equals(authName)) { auth = new ApiKeyAuth("header", "docusignApiKey"); } else { @@ -166,15 +204,52 @@ public ApiClient(String oAuthBasePath, String authName) { */ public ApiClient(String oAuthBasePath, String authName, String clientId, String secret) { this(oAuthBasePath, authName); - this.getTokenEndPoint() - .setClientId(clientId) - .setClientSecret(secret); + Authentication auth = authentications.get(authName); + if (auth instanceof OAuth) { + ((OAuth) auth).setClientId(clientId); + ((OAuth) auth).setClientSecret(secret); + } + } + + /** + * Creates an ApiClient with insecure connections enabled. + * This disables TLS certificate validation, hostname verification, and allows HTTP base paths. + *

+ * WARNING: Only use for local testing with self-signed certificates or HTTP endpoints. + * Never use in production. + *

+ * + * @return an ApiClient with insecure connections enabled + */ + public static ApiClient insecure() { + logger.warning("Insecure mode enabled - TLS certificate validation and hostname verification are disabled. Do not use in production."); + return new ApiClient(null, true, false); + } + + /** + * Creates an ApiClient with insecure connections enabled and the given base path. + * This disables TLS certificate validation, hostname verification, and allows HTTP base paths. + *

+ * WARNING: Only use for local testing with self-signed certificates or HTTP endpoints. + * Never use in production. + *

+ * + *

Example usage: + *

+   * ApiClient client = ApiClient.insecure("http://localhost:8080/restapi");
+   * 
+ * + * @param basePath The base path (HTTP or HTTPS) to create the client with. + * @return an ApiClient with insecure connections enabled and the given base path + */ + public static ApiClient insecure(String basePath) { + logger.warning("Insecure mode enabled - TLS certificate validation and hostname verification are disabled. Do not use in production."); + return new ApiClient(basePath, true, false); } /** * Build the Client used to make HTTP requests with the latest settings, * i.e. objectMapper and debugging. - * TODO: better to use the Builder Pattern? * @return API client */ public ApiClient rebuildHttpClient() { @@ -247,11 +322,30 @@ public String getBasePath() { * @return ApiClient */ public ApiClient setBasePath(String basePath) { + validateBasePath(basePath); this.basePath = basePath; this.deriveOAuthBasePathFromRestBasePath(); return this; } + /** + * Validates that the base path uses HTTPS protocol. + * HTTP connections are not allowed unless allowInsecureConnections is enabled. + * + * @param basePath The base path to validate + * @throws IllegalArgumentException if the base path uses HTTP and insecure connections are not allowed + */ + private void validateBasePath(String basePath) { + if (basePath != null && !allowInsecureConnections) { + String lowerCasePath = basePath.toLowerCase(); + if (lowerCasePath.startsWith("http://")) { + throw new IllegalArgumentException( + "HTTP connections are not allowed. Use HTTPS for secure connections. " + + "If you need HTTP for testing, use ApiClient.insecure(url)."); + } + } + } + /** * Gets the status code of the previous request. * @return Status code @@ -268,6 +362,48 @@ public Map> getResponseHeaders() { return responseHeaders; } + /** + * Returns whether insecure connections are allowed. + * @return true if insecure connections are allowed, false otherwise + */ + public boolean isAllowInsecureConnections() { + return allowInsecureConnections; + } + + /** + * Returns whether per-connection proxy authentication is enabled. + * When true, proxy credentials are applied per-connection using the Proxy-Authorization + * header instead of the JVM-wide Authenticator.setDefault(). + * @return true if per-connection proxy auth is enabled, false otherwise + */ + public boolean isPerConnectionProxyAuth() { + return perConnectionProxyAuth; + } + + /** + * Sets whether to use per-connection proxy authentication. + *

+ * By default (when false), proxy credentials from system properties (e.g. https.proxyUser) + * are configured JVM-wide via Authenticator.setDefault() with host/port scoping for + * backward compatibility. + *

+ * When set to true, proxy credentials are applied per-connection using the + * Proxy-Authorization header, which is safer and scoped to this client's connections only. + * This avoids leaking credentials to other HTTP clients running in the same JVM. + *

+ * Prefer the constructor overloads when this must be fixed at client construction time. + * If you use this setter, call it before the first request. + *

+ * Note: In a future major version, per-connection proxy auth will become the default. + * + * @param perConnectionProxyAuth true to use per-connection proxy auth instead of JVM-wide + * @return this ApiClient for method chaining + */ + public ApiClient setPerConnectionProxyAuth(boolean perConnectionProxyAuth) { + this.perConnectionProxyAuth = perConnectionProxyAuth; + return this; + } + /** * Get authentications (key: authentication name, value: authentication). * @return Map of authentication object @@ -378,7 +514,7 @@ public void setAccessToken(final String accessToken, final Long expiresIn) { return; } } - OAuth oAuth = new OAuth(null, null, null); + OAuth oAuth = new OAuth(); oAuth.setAccessToken(accessToken, expiresIn); addAuthorization("docusignAccessCode", oAuth); } @@ -523,35 +659,6 @@ public ApiClient setDateFormat(DateFormat dateFormat) { return this; } - /** - * Helper method to configure the token endpoint of the first oauth found in the authentications (there should be only one). - * @return - */ - public TokenRequestBuilder getTokenEndPoint() { - for(Authentication auth : getAuthentications().values()) { - if (auth instanceof OAuth) { - OAuth oauth = (OAuth) auth; - return oauth.getTokenRequestBuilder(); - } - } - return null; - } - - - /** - * Helper method to configure authorization endpoint of the first oauth found in the authentications (there should be only one). - * @return - */ - public AuthenticationRequestBuilder getAuthorizationEndPoint() { - for(Authentication auth : authentications.values()) { - if (auth instanceof OAuth) { - OAuth oauth = (OAuth) auth; - return oauth.getAuthenticationRequestBuilder(); - } - } - return null; - } - /** * Helper method to configure the OAuth accessCode/implicit flow parameters. * @param clientId OAuth2 client ID @@ -562,20 +669,22 @@ public void configureAuthorizationFlow(String clientId, String clientSecret, Str for(Authentication auth : authentications.values()) { if (auth instanceof OAuth) { OAuth oauth = (OAuth) auth; - oauth.getTokenRequestBuilder() - .setClientId(clientId) - .setClientSecret(clientSecret) - .setRedirectURI(redirectURI); - oauth.getAuthenticationRequestBuilder() - .setClientId(clientId) - .setRedirectURI(redirectURI); + ((OAuth) auth).setClientId(clientId); + ((OAuth) auth).setClientSecret(clientSecret); + ((OAuth) auth).setRedirectURI(redirectURI); return; } } } - public String getAuthorizationUri() throws OAuthSystemException { - return getAuthorizationEndPoint().buildQueryMessage().getLocationUri(); + public String getAuthorizationUri() { + for(Authentication auth : authentications.values()) { + if (auth instanceof OAuth) { + OAuth oauth = (OAuth) auth; + return oauth.getAuthorizationUrl(); + } + } + return null; } /** @@ -630,11 +739,9 @@ public URI getAuthorizationUri(String clientId, java.util.List scopes, S private void deriveOAuthBasePathFromRestBasePath() { if (this.basePath == null) { // this case should not happen but just in case - this.oAuthBasePath = OAuth.PRODUCTION_OAUTH_BASEPATH; - } else if (this.basePath.startsWith("https://demo") || this.basePath.startsWith("http://demo")) { this.oAuthBasePath = OAuth.DEMO_OAUTH_BASEPATH; - } else if (this.basePath.startsWith("https://stage") || this.basePath.startsWith("http://stage")) { - this.oAuthBasePath = OAuth.STAGE_OAUTH_BASEPATH; + } else if (this.basePath.startsWith("https://demo") || this.basePath.startsWith("http://demo") || this.basePath.startsWith("https://apps-d") || this.basePath.startsWith("http://apps-d")) { + this.oAuthBasePath = OAuth.DEMO_OAUTH_BASEPATH; } else { this.oAuthBasePath = OAuth.PRODUCTION_OAUTH_BASEPATH; } @@ -645,11 +752,18 @@ private String getOAuthBasePath() { } /** - * Sets the OAuth base path. Values include {@link OAuth#PRODUCTION_OAUTH_BASEPATH}, {@link OAuth#DEMO_OAUTH_BASEPATH} and custom (e.g. "account-s.docusign.com"). + * Sets the OAuth base path. Values include {@link OAuth#PRODUCTION_OAUTH_BASEPATH}, {@link OAuth#DEMO_OAUTH_BASEPATH} and custom. * @param oAuthBasePath the new value for the OAuth base path * @return this instance of the ApiClient updated with the new OAuth base path + * @throws IllegalArgumentException if the OAuth base path uses HTTP and insecure connections are not allowed */ public ApiClient setOAuthBasePath(String oAuthBasePath) { + if (oAuthBasePath != null && !allowInsecureConnections + && oAuthBasePath.toLowerCase().startsWith("http://")) { + throw new IllegalArgumentException( + "HTTP connections are not allowed for OAuth base path. Use HTTPS for secure connections. " + + "If you need HTTP for testing, use ApiClient.insecure()."); + } this.oAuthBasePath = oAuthBasePath; return this; } @@ -659,7 +773,7 @@ public ApiClient setOAuthBasePath(String oAuthBasePath) { * * @param clientId OAuth2 client ID: Identifies the client making the request. * Client applications may be scoped to a limited set of system access. - * @param clientSecret the secret key you generated when you set up the integration in DocuSign Admin console. + * @param clientSecret the secret key you generated when you set up the integration in Docusign Admin console. * @param code The authorization code that you received from the getAuthorizationUri callback. * @return OAuth.OAuthToken object. * @throws ApiException if the HTTP call status is different than 2xx. @@ -677,7 +791,7 @@ public OAuth.OAuthToken generateAccessToken(String clientId, String clientSecret Invocation.Builder invocationBuilder = target.request(); invocationBuilder = invocationBuilder - .header("Authorization", "Basic " + Base64.encodeToString(clientStr.getBytes("UTF-8"), false)) + .header("Authorization", "Basic " + Base64.getEncoder().encodeToString(clientStr.getBytes(StandardCharsets.UTF_8))) .header("Cache-Control", "no-store") .header("Pragma", "no-cache"); @@ -808,13 +922,13 @@ public String getJWTUri(String clientId, String redirectURI, String oAuthBasePat } /** - * Configures the current instance of ApiClient with a fresh OAuth JWT access token from DocuSign. + * Configures the current instance of ApiClient with a fresh OAuth JWT access token from Docusign. * @param publicKeyFilename the filename of the RSA public key * @param privateKeyFilename the filename of the RSA private key - * @param oAuthBasePath DocuSign OAuth base path (account-d.docusign.com for the developer sandbox + * @param oAuthBasePath Docusign OAuth base path (account-d.docusign.com for the developer sandbox and account.docusign.com for the production platform) - * @param clientId DocuSign OAuth Client Id (AKA Integrator Key) - * @param userId DocuSign user Id to be impersonated (This is a UUID) + * @param clientId Docusign OAuth Client Id (AKA Integrator Key) + * @param userId Docusign user Id to be impersonated (This is a UUID) * @param expiresIn number of seconds remaining before the JWT assertion is considered as invalid * @throws ApiException if there is an error while exchanging the JWT with an access token * @throws IOException if there is an issue with either the public or private file @@ -878,9 +992,9 @@ public String getJWTUri(String clientId, String redirectURI, String oAuthBasePat } /** - * Configures the current instance of ApiClient with a fresh OAuth JWT access token from DocuSign. - * @param clientId DocuSign OAuth Client Id (AKA Integrator Key) - * @param userId DocuSign user Id to be impersonated (This is a UUID) + * Configures the current instance of ApiClient with a fresh OAuth JWT access token from Docusign. + * @param clientId Docusign OAuth Client Id (AKA Integrator Key) + * @param userId Docusign user Id to be impersonated (This is a UUID) * @param scopes the list of requested scopes. Values include {@link OAuth#Scope_SIGNATURE}, {@link OAuth#Scope_EXTENDED}, {@link OAuth#Scope_IMPERSONATION}. You can also pass any advanced scope. * @param rsaPrivateKey the byte contents of the RSA private key * @param expiresIn number of seconds remaining before the JWT assertion is considered as invalid @@ -952,8 +1066,8 @@ public OAuth.OAuthToken requestJWTUserToken(String clientId, String userId, java /** * RESERVED FOR PARTNERS Request JWT Application Token. - * Configures the current instance of ApiClient with a fresh OAuth JWT access token from DocuSign - * @param clientId DocuSign OAuth Client Id (AKA Integrator Key) + * Configures the current instance of ApiClient with a fresh OAuth JWT access token from Docusign + * @param clientId Docusign OAuth Client Id (AKA Integrator Key) * @param scopes the list of requested scopes. Values include {@link OAuth#Scope_SIGNATURE}, {@link OAuth#Scope_EXTENDED}, {@link OAuth#Scope_IMPERSONATION}. You can also pass any advanced scope. * @param rsaPrivateKey the byte contents of the RSA private key * @param expiresIn number of seconds remaining before the JWT assertion is considered as invalid @@ -1388,6 +1502,12 @@ public File prepareDownloadFile(Response response) throws IOException { */ public T invokeAPI(String path, String method, List queryParams, List collectionQueryParams, Object body, Map headerParams, Map formParams, String accept, String contentType, String[] authNames, GenericType returnType) throws ApiException { + // Defense-in-depth: ensure HTTPS is used unless insecure mode is explicitly enabled + if (!allowInsecureConnections && basePath != null && basePath.toLowerCase().startsWith("http://")) { + throw new ApiException(0, "HTTPS is required. The current basePath ('" + basePath + "') uses HTTP. " + + "Use an HTTPS URL or create the client via ApiClient.insecure() for testing."); + } + updateParamsForAuth(authNames, queryParams, headerParams); // Not using `.target(this.basePath).path(path)` below, @@ -1449,7 +1569,7 @@ public T invokeAPI(String path, String method, List queryParams, List< } } - // Add DocuSign Tracking Header + // Add Docusign Tracking Header invocationBuilder = invocationBuilder.header("X-DocuSign-SDK", "Java"); if (body == null && formParams.isEmpty()) { @@ -1643,24 +1763,33 @@ protected Client buildHttpClient(boolean debugging) { throw new SecurityException("Docusign Java SDK requires TLSv1.2 Protocol"); } } catch (SecurityException se) { - System.err.println(se.getMessage()); + throw new RuntimeException("TLS requirement check failed: " + se.getMessage(), se); } catch (NoSuchAlgorithmException nsae) { - System.err.println(nsae.getMessage()); + throw new RuntimeException("TLS requirement check failed: " + nsae.getMessage(), nsae); } // Setup the SSLContext object to use for HTTPS connections to the API if (sslContext == null) { try { sslContext = SSLContext.getInstance("TLSv1.2"); - sslContext.init(null, new TrustManager[] { new SecureTrustManager() }, new SecureRandom()); + if (allowInsecureConnections) { + // Warning: This trusts all certificates - only use for testing + logger.warning("Building HTTP client with insecure SSL context - all certificates will be trusted."); + sslContext.init(null, new TrustManager[] { new InsecureTrustManager() }, new SecureRandom()); + } else { + // Use the system's default TrustManager for secure certificate validation + TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init((KeyStore) null); // Use default system trust store + sslContext.init(null, tmf.getTrustManagers(), new SecureRandom()); + } } catch (final Exception ex) { - System.err.println("failed to initialize SSL context"); + throw new RuntimeException("Failed to initialize SSL context: " + ex.getMessage(), ex); } - HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); } clientConfig.connectorProvider(new ConnectorProvider() { Proxy p = null; + String proxyAuthHeader = null; /* * Returns whether the host is part of the list of hosts that should be accessed without going through the proxy @@ -1694,6 +1823,56 @@ private boolean isNonProxyHost(String host, String nonProxyHosts) { return false; } + /** + * Configures SSL and proxy authentication on the given connection. + */ + private HttpURLConnection configureConnection(HttpURLConnection connection, Proxy usedProxy) { + if ("https".equalsIgnoreCase(connection.getURL().getProtocol())) { + HttpsURLConnection httpsConn = (HttpsURLConnection) connection; + httpsConn.setSSLSocketFactory(sslContext.getSocketFactory()); + if (allowInsecureConnections) { + httpsConn.setHostnameVerifier(new InsecureHostnameVerifier()); + } + } + // Apply proxy credentials per-connection only when explicitly opted in + if (perConnectionProxyAuth && proxyAuthHeader != null && usedProxy != null && usedProxy != Proxy.NO_PROXY) { + connection.setRequestProperty("Proxy-Authorization", proxyAuthHeader); + } + return connection; + } + + /** + * Initializes proxy credentials from system properties. + * By default, configures JVM-wide Authenticator.setDefault() with host/port scoping + * for backward compatibility. When perConnectionProxyAuth is true, only uses + * per-connection Proxy-Authorization header. + */ + private void initProxyAuth(final String host, final Integer port, String user, String password) { + proxyAuthHeader = null; + if (user != null && password != null) { + if (!perConnectionProxyAuth) { + if (host != null && port != null) { + final String proxyHost = host; + final int proxyPort = port; + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + if (getRequestorType() == RequestorType.PROXY + && getRequestingHost().equalsIgnoreCase(proxyHost) + && proxyPort == getRequestingPort()) { + return new PasswordAuthentication(user, password.toCharArray()); + } + return null; + } + }); + } + } else { + proxyAuthHeader = "Basic " + Base64.getEncoder().encodeToString( + (user + ":" + password).getBytes(StandardCharsets.UTF_8)); + } + } + } + @Override public Connector getConnector(Client client, jakarta.ws.rs.core.Configuration configuration) { HttpUrlConnectorProvider customConnProv = new HttpUrlConnectorProvider(); @@ -1705,55 +1884,34 @@ public HttpURLConnection getConnection(java.net.URL url) throws IOException { } if (isNonProxyHost(url.getHost(), System.getProperty("http.nonProxyHosts"))) { - HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(Proxy.NO_PROXY); - connection.setSSLSocketFactory(sslContext.getSocketFactory()); - return connection; + return configureConnection( + (HttpURLConnection) url.openConnection(Proxy.NO_PROXY), Proxy.NO_PROXY); } // set up the proxy/no-proxy settings if (p == null) { if (System.getProperty("https.proxyHost") != null) { // set up the proxy host and port - final String host = System.getProperty("https.proxyHost"); - final Integer port = Integer.getInteger("https.proxyPort"); - if (host != null && port != null) { - p = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port)); - } - // set up optional proxy authentication credentials - final String user = System.getProperty("https.proxyUser"); - final String password = System.getProperty("https.proxyPassword"); - if (user != null && password != null) { - Authenticator.setDefault(new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - if (getRequestorType() == RequestorType.PROXY && getRequestingHost().equalsIgnoreCase(host) && port == getRequestingPort()) { - return new PasswordAuthentication(user, password.toCharArray()); - } - return null; - } - }); - } + final String host = System.getProperty("https.proxyHost"); + final Integer port = Integer.getInteger("https.proxyPort"); + if (host != null && port != null) { + p = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port)); + } + // set up proxy authentication credentials using the configured mode + initProxyAuth(host, port, + System.getProperty("https.proxyUser"), + System.getProperty("https.proxyPassword")); } else if (System.getProperty("http.proxyHost") != null) { // set up the proxy host and port - final String host = System.getProperty("http.proxyHost"); - final Integer port = Integer.getInteger("http.proxyPort"); - if (host != null && port != null) { - p = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port)); - } - // set up optional proxy authentication credentials - final String user = System.getProperty("http.proxyUser"); - final String password = System.getProperty("http.proxyPassword"); - if (user != null && password != null) { - Authenticator.setDefault(new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - if (getRequestorType() == RequestorType.PROXY && getRequestingHost().equalsIgnoreCase(host) && port == getRequestingPort()) { - return new PasswordAuthentication(user, password.toCharArray()); - } - return null; - } - }); - } + final String host = System.getProperty("http.proxyHost"); + final Integer port = Integer.getInteger("http.proxyPort"); + if (host != null && port != null) { + p = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port)); + } + // set up proxy authentication credentials using the configured mode + initProxyAuth(host, port, + System.getProperty("http.proxyUser"), + System.getProperty("http.proxyPassword")); } // no-proxy fallback if the proxy settings are misconfigured in the system properties if (p == null) { @@ -1761,11 +1919,8 @@ protected PasswordAuthentication getPasswordAuthentication() { } } - HostnameVerifier allHostsValid = new InsecureHostnameVerifier(); - HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(p); - connection.setSSLSocketFactory(sslContext.getSocketFactory()); - connection.setHostnameVerifier(allHostsValid); - return connection; + return configureConnection( + (HttpURLConnection) url.openConnection(p), p); } }); return customConnProv.getConnector(client, configuration); @@ -1788,16 +1943,23 @@ public boolean verify(String hostname, SSLSession session) { } } - class SecureTrustManager implements X509TrustManager { + /** + * WARNING: This TrustManager trusts ALL certificates without validation. + * It should ONLY be used when allowInsecureConnections is explicitly enabled for testing. + * Using this in production is a critical security vulnerability. + */ + class InsecureTrustManager implements X509TrustManager { @Override public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { + // WARNING: No validation - trusts all client certificates } @Override public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { + // WARNING: No validation - trusts all server certificates } @Override diff --git a/src/main/java/com/docusign/monitor/client/auth/AccessTokenListener.java b/src/main/java/com/docusign/monitor/client/auth/AccessTokenListener.java index bc79753..57d5f3f 100644 --- a/src/main/java/com/docusign/monitor/client/auth/AccessTokenListener.java +++ b/src/main/java/com/docusign/monitor/client/auth/AccessTokenListener.java @@ -1,7 +1,7 @@ package com.docusign.monitor.client.auth; -import org.apache.oltu.oauth2.common.token.BasicOAuthToken; +import com.docusign.monitor.client.auth.OAuth.OAuthToken; public interface AccessTokenListener { - void notify(BasicOAuthToken token); -} + void notify(OAuthToken token); +} \ No newline at end of file diff --git a/src/main/java/com/docusign/monitor/client/auth/JWTUtils.java b/src/main/java/com/docusign/monitor/client/auth/JWTUtils.java index 596b348..c0b250c 100644 --- a/src/main/java/com/docusign/monitor/client/auth/JWTUtils.java +++ b/src/main/java/com/docusign/monitor/client/auth/JWTUtils.java @@ -34,10 +34,10 @@ public class JWTUtils { * Helper method to create a JWT token for the JWT flow. * * @param rsaPrivateKey the byte contents of the RSA private key - * @param oAuthBasePath DocuSign OAuth base path (account-d.docusign.com for the developer sandbox + * @param oAuthBasePath Docusign OAuth base path (account-d.docusign.com for the developer sandbox * and account.docusign.com for the production platform) - * @param clientId DocuSign OAuth Client Id (AKA Integrator Key) - * @param userId DocuSign user Id to be impersonated (This is a UUID) + * @param clientId Docusign OAuth Client Id (AKA Integrator Key) + * @param userId Docusign user Id to be impersonated (This is a UUID) * @param expiresIn number of seconds remaining before the JWT assertion is considered as invalid * @param scopes space-separated string that represents the list of scopes to grant to the OAuth * token. @@ -88,10 +88,10 @@ public static String generateJWTAssertionFromByteArray( * * @param publicKeyFilename the filename of the RSA public key * @param privateKeyFilename the filename of the RSA private key - * @param oAuthBasePath DocuSign OAuth base path (account-d.docusign.com for the developer sandbox + * @param oAuthBasePath Docusign OAuth base path (account-d.docusign.com for the developer sandbox * and account.docusign.com for the production platform) - * @param clientId DocuSign OAuth Client Id (AKA Integrator Key) - * @param userId DocuSign user Id to be impersonated (This is a UUID) + * @param clientId Docusign OAuth Client Id (AKA Integrator Key) + * @param userId Docusign user Id to be impersonated (This is a UUID) * @param expiresIn number of seconds remaining before the JWT assertion is considered as invalid * @return a fresh JWT token * @throws JWTCreationException if not able to create a JWT token from the input parameters @@ -113,10 +113,10 @@ public static String generateJWTAssertion( * * @param publicKeyFilename the filename of the RSA public key * @param privateKeyFilename the filename of the RSA private key - * @param oAuthBasePath DocuSign OAuth base path (account-d.docusign.com for the developer sandbox + * @param oAuthBasePath Docusign OAuth base path (account-d.docusign.com for the developer sandbox * and account.docusign.com for the production platform) - * @param clientId DocuSign OAuth Client Id (AKA Integrator Key) - * @param userId DocuSign user Id to be impersonated (This is a UUID) + * @param clientId Docusign OAuth Client Id (AKA Integrator Key) + * @param userId Docusign user Id to be impersonated (This is a UUID) * @param expiresIn number of seconds remaining before the JWT assertion is considered as invalid * @param scopes space-separated string that represents the list of scopes to grant to the OAuth * token. diff --git a/src/main/java/com/docusign/monitor/client/auth/OAuth.java b/src/main/java/com/docusign/monitor/client/auth/OAuth.java index 4fcae99..f5397e4 100644 --- a/src/main/java/com/docusign/monitor/client/auth/OAuth.java +++ b/src/main/java/com/docusign/monitor/client/auth/OAuth.java @@ -1,26 +1,23 @@ package com.docusign.monitor.client.auth; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.text.DateFormat; +import java.util.*; -import jakarta.ws.rs.client.ClientBuilder; +import com.docusign.monitor.client.RFC3339DateFormat; + +import jakarta.ws.rs.client.*; +import jakarta.ws.rs.core.Form; +import jakarta.ws.rs.core.GenericType; +import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import com.docusign.monitor.client.ApiException; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import org.apache.oltu.oauth2.client.OAuthClient; -import org.apache.oltu.oauth2.client.URLConnectionClient; -import org.apache.oltu.oauth2.client.request.OAuthClientRequest; -import org.apache.oltu.oauth2.client.response.OAuthJSONAccessTokenResponse; -import org.apache.oltu.oauth2.client.request.OAuthClientRequest.AuthenticationRequestBuilder; -import org.apache.oltu.oauth2.client.request.OAuthClientRequest.TokenRequestBuilder; -import org.apache.oltu.oauth2.common.message.types.GrantType; -import org.apache.oltu.oauth2.common.token.BasicOAuthToken; import com.docusign.monitor.client.Pair; import com.fasterxml.jackson.annotation.JsonProperty; -import jakarta.ws.rs.client.Client; import io.swagger.v3.oas.annotations.media.Schema; @@ -50,39 +47,43 @@ public class OAuth implements Authentication { public final static String PRODUCTION_OAUTH_BASEPATH = "account.docusign.com"; /** sandbox/demo base path. */ public final static String DEMO_OAUTH_BASEPATH = "account-d.docusign.com"; - /** stage base path. */ - public final static String STAGE_OAUTH_BASEPATH = "account-s.docusign.com"; // OAuth grant types /** JWT grant type. */ public final static String GRANT_TYPE_JWT = "urn:ietf:params:oauth:grant-type:jwt-bearer"; + // Client ID and secret for oauth + private String clientId = null; + private String clientSecret = null; + + // auth, token and redirect urls + private String authorizationUrl = null; + private String tokenUrl = null; + private String redirectURI = null; + + // scopes and grant type + private String scope = null; + private OAuthFlow grantType = null; + private volatile String accessToken; + private volatile String refreshToken; + private volatile String authCode; + private volatile String jwtAssertion; + private Long expirationTimeMillis; - private OAuthClient oauthClient; - private TokenRequestBuilder tokenRequestBuilder; - private AuthenticationRequestBuilder authenticationRequestBuilder; private AccessTokenListener accessTokenListener; - /** + private Client httpClient; + + + /** * OAuth constructor. * */ - public OAuth() { - this(null, null, null); - } + public OAuth() { } - /** - * OAuth constructor. - * - * @param client The client to use - * @param tokenRequestBuilder The request builder - * @param authenticationRequestBuilder The auth request builder - */ - public OAuth(Client client, TokenRequestBuilder tokenRequestBuilder, AuthenticationRequestBuilder authenticationRequestBuilder) { - this.oauthClient = new OAuthClient(new URLConnectionClient()); - this.tokenRequestBuilder = tokenRequestBuilder; - this.authenticationRequestBuilder = authenticationRequestBuilder; + public OAuth(Client httpClient) { + this.httpClient = httpClient; } /** @@ -95,26 +96,11 @@ public OAuth(Client client, TokenRequestBuilder tokenRequestBuilder, Authenticat * @param scopes The scopes to use */ public OAuth(Client client, OAuthFlow flow, String authorizationUrl, String tokenUrl, String scopes) { - this(client, OAuthClientRequest.tokenLocation(tokenUrl).setScope(scopes), OAuthClientRequest.authorizationLocation(authorizationUrl).setScope(scopes)); - - switch (flow) { - case accessCode: - tokenRequestBuilder.setGrantType(GrantType.AUTHORIZATION_CODE); - authenticationRequestBuilder.setResponseType(OAuth.CODE); - break; - case implicit: - tokenRequestBuilder.setGrantType(GrantType.IMPLICIT); - authenticationRequestBuilder.setResponseType(OAuth.TOKEN); - break; - case password: - tokenRequestBuilder.setGrantType(GrantType.PASSWORD); - break; - case application: - tokenRequestBuilder.setGrantType(GrantType.CLIENT_CREDENTIALS); - break; - default: - break; - } + this.httpClient = client; + setScope(scopes); + setGrantType(flow); + setAuthorizationUrl(authorizationUrl); + setTokenUrl(tokenUrl); } /** @@ -155,30 +141,33 @@ public void applyToParams(List queryParams, Map headerPara * */ public synchronized void updateAccessToken() throws ApiException { - OAuthJSONAccessTokenResponse accessTokenResponse; + OAuthToken oauthToken = null; try { - accessTokenResponse = oauthClient.accessToken(tokenRequestBuilder.buildBodyMessage()); + switch (getGrantType()) { + case accessCode: // Authorization Grant + oauthToken = generateAccessToken(); + break; + case jwt: // JWT Grant + oauthToken = requestJWTUserToken(); + break; + default: // Implicit Grant - token will already be set by consuming app using setAccessToken() + break; + } } catch (Exception e) { throw new ApiException(e.getMessage()); } - if (accessTokenResponse != null) + if (oauthToken != null) { - // FIXME: This does not work in case of non HTTP 200 :-( oauthClient needs to return the plain HTTP resonse - if (accessTokenResponse.getResponseCode() != Response.Status.OK.getStatusCode()) - { - throw new ApiException("Error while requesting an access token, received HTTP code: " + accessTokenResponse.getResponseCode()); - } - - if (accessTokenResponse.getAccessToken() == null) { + if (oauthToken.getAccessToken() == null) { throw new ApiException("Error while requesting an access token. No 'access_token' found."); } - if (accessTokenResponse.getExpiresIn() == null) { + if (oauthToken.getExpiresIn() == null) { throw new ApiException("Error while requesting an access token. No 'expires_in' found."); } - setAccessToken(accessTokenResponse.getAccessToken(), accessTokenResponse.getExpiresIn()); + setAccessToken(oauthToken.getAccessToken(), Long.valueOf(oauthToken.getExpiresIn())); if (this.accessTokenListener != null) { - this.accessTokenListener.notify((BasicOAuthToken)accessTokenResponse.getOAuthToken()); + this.accessTokenListener.notify(oauthToken); } } else { // in case of HTTP error codes accessTokenResponse is null, thus no check of accessTokenResponse.getResponseCode() possible :-( @@ -186,6 +175,130 @@ public synchronized void updateAccessToken() throws ApiException { } } + + /** + * Configures the current instance of ApiClient with a fresh OAuth JWT access token from DocuSign. + * @return OAuth.OAuthToken object. + * @throws IllegalArgumentException if one of the arguments is invalid + * @throws ApiException if there is an error while exchanging the JWT with an access token + * @throws IOException if there is an issue with either the public or private file + */ + public OAuth.OAuthToken requestJWTUserToken() throws IllegalArgumentException, ApiException, IOException { + java.util.Map form = new java.util.HashMap<>(); + form.put("assertion", getJwtAssertion()); + form.put("grant_type", OAuth.GRANT_TYPE_JWT); + + WebTarget target = httpClient.target(getTokenUrl()); + Invocation.Builder invocationBuilder = target.request(); + invocationBuilder = invocationBuilder + .header("Cache-Control", "no-store") + .header("Pragma", "no-cache"); + + Entity entity = serialize(null, form, MediaType.APPLICATION_FORM_URLENCODED); + + Response response = null; + + try { + response = invocationBuilder.post(entity); + + if (response.getStatusInfo().getFamily() != Response.Status.Family.SUCCESSFUL) { + String message = "error"; + String respBody = null; + if (response.hasEntity()) { + try { + respBody = String.valueOf(response.readEntity(String.class)); + message = "Error while requesting server, received a non successful HTTP code " + response.getStatusInfo().getStatusCode() + " with response Body: '" + respBody + "'"; + } catch (RuntimeException e) { + // e.printStackTrace(); + } + } + throw new ApiException( + response.getStatusInfo().getStatusCode(), + message, + buildResponseHeaders(response), + respBody); + } + + GenericType returnType = new GenericType() {}; + OAuth.OAuthToken oAuthToken = deserialize(response, returnType); + if (oAuthToken.getAccessToken() == null || "".equals(oAuthToken.getAccessToken()) || oAuthToken.getExpiresIn() <= 0) { + throw new ApiException("Error while requesting an access token: " + response.toString()); + } + return oAuthToken; + } finally { + try { + if (response != null) { + response.close(); + } + } catch (Exception e) { + // it's not critical, since the response object is local in method invokeAPI; that's fine, just continue + } + } + } + + /** + * Helper method to configure the OAuth accessCode/implicit flow parameters. + * + * @return OAuth.OAuthToken object. + * @throws ApiException if the HTTP call status is different than 2xx. + * @throws IOException if there is a problem while parsing the reponse object. + * @see OAuth.OAuthToken + */ + public OAuth.OAuthToken generateAccessToken() throws ApiException, IOException { + String clientId = getClientId(); + String clientSecret = getClientSecret(); + String code = getAuthCode(); + String clientStr = (clientId == null ? "" : clientId) + ":" + (clientSecret == null ? "" : clientSecret); + java.util.Map form = new java.util.HashMap<>(); + form.put("code", code); + form.put("grant_type", "authorization_code"); + + WebTarget target = httpClient.target(getTokenUrl()); + + Invocation.Builder invocationBuilder = target.request(); + invocationBuilder = invocationBuilder + .header("Authorization", "Basic " + Base64.getEncoder().encodeToString(clientStr.getBytes(StandardCharsets.UTF_8))) + .header("Cache-Control", "no-store") + .header("Pragma", "no-cache"); + + Entity entity = serialize(null, form, MediaType.APPLICATION_FORM_URLENCODED); + + Response response = null; + + try { + response = invocationBuilder.post(entity); + + if (response.getStatusInfo().getFamily() != Response.Status.Family.SUCCESSFUL) { + String message = "error"; + String respBody = null; + if (response.hasEntity()) { + try { + respBody = String.valueOf(response.readEntity(String.class)); + message = "Error while requesting server, received a non successful HTTP code " + response.getStatusInfo().getStatusCode() + " with response Body: '" + respBody + "'"; + } catch (RuntimeException e) { + // e.printStackTrace(); + } + } + throw new ApiException( + response.getStatusInfo().getStatusCode(), + message, + buildResponseHeaders(response), + respBody); + } + + GenericType returnType = new GenericType() {}; + return deserialize(response, returnType); + } finally { + try { + if (response != null) { + response.close(); + } + } catch (Exception e) { + // it's not critical, since the response object is local in method invokeAPI; that's fine, just continue + } + } + } + /** * registerAccessTokenListener method. * @@ -204,43 +317,181 @@ public synchronized String getAccessToken() { return accessToken; } + public Long getExpirationTimeMillis() { + return expirationTimeMillis; + } + + public void setExpirationTimeMillis(Long expirationTimeMillis) { + this.expirationTimeMillis = expirationTimeMillis; + } + public synchronized void setAccessToken(String accessToken, Long expiresIn) { this.accessToken = accessToken; this.expirationTimeMillis = System.currentTimeMillis() + expiresIn * MILLIS_PER_SECOND; } - public TokenRequestBuilder getTokenRequestBuilder() { - return tokenRequestBuilder; + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; } - public void setTokenRequestBuilder(TokenRequestBuilder tokenRequestBuilder) { - this.tokenRequestBuilder = tokenRequestBuilder; + public String getClientSecret() { + return clientSecret; } - public AuthenticationRequestBuilder getAuthenticationRequestBuilder() { - return authenticationRequestBuilder; + public void setClientSecret(String clientSecret) { + this.clientSecret = clientSecret; } - public void setAuthenticationRequestBuilder(AuthenticationRequestBuilder authenticationRequestBuilder) { - this.authenticationRequestBuilder = authenticationRequestBuilder; + public String getAuthorizationUrl() { + return authorizationUrl; } - public OAuthClient getOauthClient() { - return oauthClient; + public void setAuthorizationUrl(String authorizationUrl) { + this.authorizationUrl = authorizationUrl; } - public void setOauthClient(OAuthClient oauthClient) { - this.oauthClient = oauthClient; + public String getTokenUrl() { + return tokenUrl; } - public void setOauthClient(Client client) { - this.oauthClient = new OAuthClient(new URLConnectionClient()); + public void setTokenUrl(String tokenUrl) { + this.tokenUrl = tokenUrl; + } + + public String getRedirectURI() { + return redirectURI; + } + + public void setRedirectURI(String redirectURI) { + this.redirectURI = redirectURI; + } + + public String getScope() { + return scope; + } + + public void setScope(String scope) { + this.scope = scope; + } + + public OAuthFlow getGrantType() { + return grantType; + } + + public void setGrantType(OAuthFlow grantType) { + this.grantType = grantType; + } + + public String getJwtAssertion() { + return jwtAssertion; + } + + public void setJwtAssertion(String jwtAssertion) { + this.jwtAssertion = jwtAssertion; + } + + public String getAuthCode() { + return authCode; + } + + public void setAuthCode(String authCode) { + this.authCode = authCode; + } + + + protected Map> buildResponseHeaders(Response response) { + Map> responseHeaders = new HashMap>(); + for (Map.Entry> entry: response.getHeaders().entrySet()) { + List values = entry.getValue(); + List headers = new ArrayList(); + for (Object o : values) { + headers.add(String.valueOf(o)); + } + responseHeaders.put(entry.getKey(), headers); + } + return responseHeaders; + } + + /** + * Serialize the given Java object into string entity according the given + * Content-Type (only JSON is supported for now). + * @param obj Object + * @param formParams Form parameters + * @param contentType Context type + * @return Entity + * @throws ApiException API exception + */ + public Entity serialize(Object obj, Map formParams, String contentType) throws ApiException { + Entity entity; + if (contentType.startsWith("application/x-www-form-urlencoded")) { + Form form = new Form(); + for (Map.Entry param: formParams.entrySet()) { + form.param(param.getKey(), parameterToString(param.getValue())); + } + entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE); + } else { + // We let jersey handle the serialization + entity = Entity.entity(obj, contentType); + } + return entity; + } + + /** + * Format the given parameter object into string. + * @param param Object + * @return Object in string format + */ + public String parameterToString(Object param) { + if (param == null) { + return ""; + } else if (param instanceof Date) { + DateFormat dateFormat = new RFC3339DateFormat(); + return dateFormat.format((Date) param); + } else if (param instanceof Collection) { + StringBuilder b = new StringBuilder(); + for(Object o : (Collection)param) { + if(b.length() > 0) { + b.append(','); + } + b.append(String.valueOf(o)); + } + return b.toString(); + } else { + return String.valueOf(param); + } + } + + /** + * Deserialize response body to Java object according to the Content-Type. + * @param Type + * @param response Response + * @param returnType Return type + * @return Deserialize object + * @throws ApiException API exception + */ + @SuppressWarnings("unchecked") + public T deserialize(Response response, GenericType returnType) throws ApiException { + if (response == null || returnType == null) { + return null; + } + + String contentType = null; + List contentTypes = response.getHeaders().get("Content-Type"); + if (contentTypes != null && !contentTypes.isEmpty()) { + contentType = String.valueOf(contentTypes.get(0)); + } + + return response.readEntity(returnType); } /** * * OAuthToken model with the following properties. - *
accessToken: the token you will use in the Authorization header of calls to the DocuSign API. + *
accessToken: the token you will use in the Authorization header of calls to the Docusign API. *
tokenType: this is the type of the accessToken. It is usually "Bearer". *
refreshToken: a token you can use to get a new accessToken without requiring user interaction. *
expiresIn: the number of seconds before the accessToken expires. @@ -260,6 +511,9 @@ public static class OAuthToken { @JsonProperty("expires_in") private Long expiresIn = 0L; + @JsonProperty("scope") + private String scope = null; + public OAuthToken accessToken(String accessToken) { this.accessToken = accessToken; return this; @@ -336,6 +590,20 @@ public void setExpiresIn(Long expiresIn) { this.expiresIn = expiresIn; } + /** + * Get scope. + * + * @return scope + **/ + @Schema(example = "null", description = "") + public String getScope() { + return scope; + } + + public void setScope(String scope) { + this.scope = scope; + } + @Override public boolean equals(java.lang.Object o) { if (this == o) { @@ -476,8 +744,8 @@ private String toIndentedString(java.lang.Object o) { /** * * Organization model with the below properties. - *
organizationId: the organization ID GUID if DocuSign Org Admin is enabled. - *
links: this is list of organization direct links associated with the DocuSign account. + *
organizationId: the organization ID GUID if Docusign Org Admin is enabled. + *
links: this is list of organization direct links associated with the Docusign account. * */ @JsonIgnoreProperties(ignoreUnknown = true) @@ -578,8 +846,8 @@ private String toIndentedString(java.lang.Object o) { *
isDefault: whether this is the default account, when the user has access to multiple accounts. *
accountName: the human-readable name of the account. *
baseUri: the base URI associated with this account. - * It also tells which DocuSign data center the account is hosted on. - *
organization: If DocuSign Org Admin is enabled on this account, + * It also tells which Docusign data center the account is hosted on. + *
organization: If Docusign Org Admin is enabled on this account, * this property contains the organization information. * */ @@ -745,7 +1013,7 @@ private String toIndentedString(java.lang.Object o) { * * UserInfo model with the below properties. *
sub: the user ID GUID. - *
accounts: this is list of DocuSign accounts associated with the current user. + *
accounts: this is list of Docusign accounts associated with the current user. *
name: the user's full name. *
givenName: the user's given name. *
familyName: the user's family name. diff --git a/src/main/java/com/docusign/monitor/client/auth/OAuthFlow.java b/src/main/java/com/docusign/monitor/client/auth/OAuthFlow.java index d444acb..45885cc 100644 --- a/src/main/java/com/docusign/monitor/client/auth/OAuthFlow.java +++ b/src/main/java/com/docusign/monitor/client/auth/OAuthFlow.java @@ -8,5 +8,5 @@ */ public enum OAuthFlow { - accessCode, implicit, password, application + accessCode, implicit, password, application, jwt } diff --git a/src/main/java/com/docusign/monitor/model/Browser.java b/src/main/java/com/docusign/monitor/model/Browser.java new file mode 100644 index 0000000..3dc9029 --- /dev/null +++ b/src/main/java/com/docusign/monitor/model/Browser.java @@ -0,0 +1,134 @@ +package com.docusign.monitor.model; + +import java.util.Objects; +import java.util.Arrays; +import com.docusign.monitor.model.Version; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import io.swagger.v3.oas.annotations.media.Schema; +import java.io.Serializable; + +/** + * Browser. + * + */ + +public class Browser implements Serializable { + private static final long serialVersionUID = 1L; + + @JsonProperty("family") + private String family = null; + + @JsonProperty("version") + private Version version = null; + + + /** + * family. + * + * @return Browser + **/ + public Browser family(String family) { + this.family = family; + return this; + } + + /** + * Get family. + * @return family + **/ + @Schema(description = "") + public String getFamily() { + return family; + } + + /** + * setFamily. + **/ + public void setFamily(String family) { + this.family = family; + } + + + /** + * version. + * + * @return Browser + **/ + public Browser version(Version version) { + this.version = version; + return this; + } + + /** + * Get version. + * @return version + **/ + @Schema(description = "") + public Version getVersion() { + return version; + } + + /** + * setVersion. + **/ + public void setVersion(Version version) { + this.version = version; + } + + + /** + * Compares objects. + * + * @return true or false depending on comparison result. + */ + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Browser browser = (Browser) o; + return Objects.equals(this.family, browser.family) && + Objects.equals(this.version, browser.version); + } + + /** + * Returns the HashCode. + */ + @Override + public int hashCode() { + return Objects.hash(family, version); + } + + + /** + * Converts the given object to string. + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Browser {\n"); + + sb.append(" family: ").append(toIndentedString(family)).append("\n"); + sb.append(" version: ").append(toIndentedString(version)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/com/docusign/monitor/model/Device.java b/src/main/java/com/docusign/monitor/model/Device.java new file mode 100644 index 0000000..5ba398e --- /dev/null +++ b/src/main/java/com/docusign/monitor/model/Device.java @@ -0,0 +1,165 @@ +package com.docusign.monitor.model; + +import java.util.Objects; +import java.util.Arrays; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import io.swagger.v3.oas.annotations.media.Schema; +import java.io.Serializable; + +/** + * Device. + * + */ + +public class Device implements Serializable { + private static final long serialVersionUID = 1L; + + @JsonProperty("family") + private String family = null; + + @JsonProperty("brand") + private String brand = null; + + @JsonProperty("model") + private String model = null; + + + /** + * family. + * + * @return Device + **/ + public Device family(String family) { + this.family = family; + return this; + } + + /** + * Get family. + * @return family + **/ + @Schema(description = "") + public String getFamily() { + return family; + } + + /** + * setFamily. + **/ + public void setFamily(String family) { + this.family = family; + } + + + /** + * brand. + * + * @return Device + **/ + public Device brand(String brand) { + this.brand = brand; + return this; + } + + /** + * Get brand. + * @return brand + **/ + @Schema(description = "") + public String getBrand() { + return brand; + } + + /** + * setBrand. + **/ + public void setBrand(String brand) { + this.brand = brand; + } + + + /** + * model. + * + * @return Device + **/ + public Device model(String model) { + this.model = model; + return this; + } + + /** + * Get model. + * @return model + **/ + @Schema(description = "") + public String getModel() { + return model; + } + + /** + * setModel. + **/ + public void setModel(String model) { + this.model = model; + } + + + /** + * Compares objects. + * + * @return true or false depending on comparison result. + */ + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Device device = (Device) o; + return Objects.equals(this.family, device.family) && + Objects.equals(this.brand, device.brand) && + Objects.equals(this.model, device.model); + } + + /** + * Returns the HashCode. + */ + @Override + public int hashCode() { + return Objects.hash(family, brand, model); + } + + + /** + * Converts the given object to string. + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Device {\n"); + + sb.append(" family: ").append(toIndentedString(family)).append("\n"); + sb.append(" brand: ").append(toIndentedString(brand)).append("\n"); + sb.append(" model: ").append(toIndentedString(model)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/com/docusign/monitor/model/IpAddressLocation.java b/src/main/java/com/docusign/monitor/model/IpAddressLocation.java new file mode 100644 index 0000000..311f5d6 --- /dev/null +++ b/src/main/java/com/docusign/monitor/model/IpAddressLocation.java @@ -0,0 +1,229 @@ +package com.docusign.monitor.model; + +import java.util.Objects; +import java.util.Arrays; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import io.swagger.v3.oas.annotations.media.Schema; +import java.io.Serializable; + +/** + * IpAddressLocation. + * + */ + +public class IpAddressLocation implements Serializable { + private static final long serialVersionUID = 1L; + + @JsonProperty("latitude") + private Double latitude = null; + + @JsonProperty("longitude") + private Double longitude = null; + + @JsonProperty("country") + private String country = null; + + @JsonProperty("state") + private String state = null; + + @JsonProperty("city") + private String city = null; + + + /** + * latitude. + * + * @return IpAddressLocation + **/ + public IpAddressLocation latitude(Double latitude) { + this.latitude = latitude; + return this; + } + + /** + * Get latitude. + * @return latitude + **/ + @Schema(description = "") + public Double getLatitude() { + return latitude; + } + + /** + * setLatitude. + **/ + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + + /** + * longitude. + * + * @return IpAddressLocation + **/ + public IpAddressLocation longitude(Double longitude) { + this.longitude = longitude; + return this; + } + + /** + * Get longitude. + * @return longitude + **/ + @Schema(description = "") + public Double getLongitude() { + return longitude; + } + + /** + * setLongitude. + **/ + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + + /** + * country. + * + * @return IpAddressLocation + **/ + public IpAddressLocation country(String country) { + this.country = country; + return this; + } + + /** + * Get country. + * @return country + **/ + @Schema(description = "") + public String getCountry() { + return country; + } + + /** + * setCountry. + **/ + public void setCountry(String country) { + this.country = country; + } + + + /** + * state. + * + * @return IpAddressLocation + **/ + public IpAddressLocation state(String state) { + this.state = state; + return this; + } + + /** + * Get state. + * @return state + **/ + @Schema(description = "") + public String getState() { + return state; + } + + /** + * setState. + **/ + public void setState(String state) { + this.state = state; + } + + + /** + * city. + * + * @return IpAddressLocation + **/ + public IpAddressLocation city(String city) { + this.city = city; + return this; + } + + /** + * Get city. + * @return city + **/ + @Schema(description = "") + public String getCity() { + return city; + } + + /** + * setCity. + **/ + public void setCity(String city) { + this.city = city; + } + + + /** + * Compares objects. + * + * @return true or false depending on comparison result. + */ + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + IpAddressLocation ipAddressLocation = (IpAddressLocation) o; + return Objects.equals(this.latitude, ipAddressLocation.latitude) && + Objects.equals(this.longitude, ipAddressLocation.longitude) && + Objects.equals(this.country, ipAddressLocation.country) && + Objects.equals(this.state, ipAddressLocation.state) && + Objects.equals(this.city, ipAddressLocation.city); + } + + /** + * Returns the HashCode. + */ + @Override + public int hashCode() { + return Objects.hash(latitude, longitude, country, state, city); + } + + + /** + * Converts the given object to string. + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class IpAddressLocation {\n"); + + sb.append(" latitude: ").append(toIndentedString(latitude)).append("\n"); + sb.append(" longitude: ").append(toIndentedString(longitude)).append("\n"); + sb.append(" country: ").append(toIndentedString(country)).append("\n"); + sb.append(" state: ").append(toIndentedString(state)).append("\n"); + sb.append(" city: ").append(toIndentedString(city)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/com/docusign/monitor/model/Os.java b/src/main/java/com/docusign/monitor/model/Os.java new file mode 100644 index 0000000..e0ea3b2 --- /dev/null +++ b/src/main/java/com/docusign/monitor/model/Os.java @@ -0,0 +1,134 @@ +package com.docusign.monitor.model; + +import java.util.Objects; +import java.util.Arrays; +import com.docusign.monitor.model.Version; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import io.swagger.v3.oas.annotations.media.Schema; +import java.io.Serializable; + +/** + * Os. + * + */ + +public class Os implements Serializable { + private static final long serialVersionUID = 1L; + + @JsonProperty("family") + private String family = null; + + @JsonProperty("version") + private Version version = null; + + + /** + * family. + * + * @return Os + **/ + public Os family(String family) { + this.family = family; + return this; + } + + /** + * Get family. + * @return family + **/ + @Schema(description = "") + public String getFamily() { + return family; + } + + /** + * setFamily. + **/ + public void setFamily(String family) { + this.family = family; + } + + + /** + * version. + * + * @return Os + **/ + public Os version(Version version) { + this.version = version; + return this; + } + + /** + * Get version. + * @return version + **/ + @Schema(description = "") + public Version getVersion() { + return version; + } + + /** + * setVersion. + **/ + public void setVersion(Version version) { + this.version = version; + } + + + /** + * Compares objects. + * + * @return true or false depending on comparison result. + */ + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Os os = (Os) o; + return Objects.equals(this.family, os.family) && + Objects.equals(this.version, os.version); + } + + /** + * Returns the HashCode. + */ + @Override + public int hashCode() { + return Objects.hash(family, version); + } + + + /** + * Converts the given object to string. + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Os {\n"); + + sb.append(" family: ").append(toIndentedString(family)).append("\n"); + sb.append(" version: ").append(toIndentedString(version)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/com/docusign/monitor/model/StreamResponse.java b/src/main/java/com/docusign/monitor/model/StreamResponse.java new file mode 100644 index 0000000..a11d6fc --- /dev/null +++ b/src/main/java/com/docusign/monitor/model/StreamResponse.java @@ -0,0 +1,147 @@ +package com.docusign.monitor.model; + +import java.util.Objects; +import java.util.Arrays; +import com.docusign.monitor.model.StreamingEventRow; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import io.swagger.v3.oas.annotations.media.Schema; +import java.io.Serializable; + +/** + * StreamResponse. + * + */ + +public class StreamResponse implements Serializable { + private static final long serialVersionUID = 1L; + + @JsonProperty("resultData") + private java.util.List resultData = null; + + @JsonProperty("endCursor") + private String endCursor = null; + + + /** + * resultData. + * + * @return StreamResponse + **/ + public StreamResponse resultData(java.util.List resultData) { + this.resultData = resultData; + return this; + } + + /** + * addResultDataItem. + * + * @return StreamResponse + **/ + public StreamResponse addResultDataItem(StreamingEventRow resultDataItem) { + if (this.resultData == null) { + this.resultData = new java.util.ArrayList<>(); + } + this.resultData.add(resultDataItem); + return this; + } + + /** + * Get resultData. + * @return resultData + **/ + @Schema(description = "") + public java.util.List getResultData() { + return resultData; + } + + /** + * setResultData. + **/ + public void setResultData(java.util.List resultData) { + this.resultData = resultData; + } + + + /** + * endCursor. + * + * @return StreamResponse + **/ + public StreamResponse endCursor(String endCursor) { + this.endCursor = endCursor; + return this; + } + + /** + * Get endCursor. + * @return endCursor + **/ + @Schema(description = "") + public String getEndCursor() { + return endCursor; + } + + /** + * setEndCursor. + **/ + public void setEndCursor(String endCursor) { + this.endCursor = endCursor; + } + + + /** + * Compares objects. + * + * @return true or false depending on comparison result. + */ + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + StreamResponse streamResponse = (StreamResponse) o; + return Objects.equals(this.resultData, streamResponse.resultData) && + Objects.equals(this.endCursor, streamResponse.endCursor); + } + + /** + * Returns the HashCode. + */ + @Override + public int hashCode() { + return Objects.hash(resultData, endCursor); + } + + + /** + * Converts the given object to string. + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class StreamResponse {\n"); + + sb.append(" resultData: ").append(toIndentedString(resultData)).append("\n"); + sb.append(" endCursor: ").append(toIndentedString(endCursor)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/com/docusign/monitor/model/StreamingEventRow.java b/src/main/java/com/docusign/monitor/model/StreamingEventRow.java new file mode 100644 index 0000000..c66f241 --- /dev/null +++ b/src/main/java/com/docusign/monitor/model/StreamingEventRow.java @@ -0,0 +1,1173 @@ +package com.docusign.monitor.model; + +import java.util.Objects; +import java.util.Arrays; +import com.docusign.monitor.model.IpAddressLocation; +import com.docusign.monitor.model.UserAgentClientInfo; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.OffsetDateTime; +import java.io.Serializable; + +/** + * StreamingEventRow. + * + */ + +public class StreamingEventRow implements Serializable { + private static final long serialVersionUID = 1L; + + @JsonProperty("timestamp") + private String timestamp = null; + + @JsonProperty("eventId") + private String eventId = null; + + @JsonProperty("site") + private String site = null; + + @JsonProperty("accountId") + private String accountId = null; + + @JsonProperty("organizationId") + private String organizationId = null; + + @JsonProperty("userId") + private String userId = null; + + @JsonProperty("integratorKey") + private String integratorKey = null; + + @JsonProperty("userAgent") + private String userAgent = null; + + @JsonProperty("userAgentClientInfo") + private UserAgentClientInfo userAgentClientInfo = null; + + @JsonProperty("ipAddress") + private String ipAddress = null; + + @JsonProperty("ipAddressLocation") + private IpAddressLocation ipAddressLocation = null; + + @JsonProperty("object") + private String object = null; + + @JsonProperty("action") + private String action = null; + + @JsonProperty("property") + private String property = null; + + @JsonProperty("field") + private String field = null; + + @JsonProperty("result") + private String result = null; + + @JsonProperty("source") + private String source = null; + + @JsonProperty("isUserMemberOfDomain") + private Boolean isUserMemberOfDomain = null; + + @JsonProperty("referencedUserIsMemberOfDomain") + private Boolean referencedUserIsMemberOfDomain = null; + + @JsonProperty("referencedUserId") + private String referencedUserId = null; + + @JsonProperty("proxyStatus") + private String proxyStatus = null; + + @JsonProperty("proxyType") + private String proxyType = null; + + @JsonProperty("proxyLevel") + private String proxyLevel = null; + + @JsonProperty("latitude") + private Double latitude = null; + + @JsonProperty("longitude") + private Double longitude = null; + + @JsonProperty("city") + private String city = null; + + @JsonProperty("state") + private String state = null; + + @JsonProperty("country") + private String country = null; + + @JsonProperty("device") + private String device = null; + + @JsonProperty("browser") + private String browser = null; + + @JsonProperty("os") + private String os = null; + + @JsonProperty("affectedUserId") + private String affectedUserId = null; + + @JsonProperty("affectedUserIsMemberOfDomain") + private Boolean affectedUserIsMemberOfDomain = null; + + @JsonProperty("data") + private java.util.Map data = null; + + + /** + * timestamp. + * + * @return StreamingEventRow + **/ + public StreamingEventRow timestamp(String timestamp) { + this.timestamp = timestamp; + return this; + } + + /** + * Get timestamp. + * @return timestamp + **/ + @Schema(description = "") + public String getTimestamp() { + return timestamp; + } + + /** + * setTimestamp. + **/ + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + + /** + * eventId. + * + * @return StreamingEventRow + **/ + public StreamingEventRow eventId(String eventId) { + this.eventId = eventId; + return this; + } + + /** + * Get eventId. + * @return eventId + **/ + @Schema(description = "") + public String getEventId() { + return eventId; + } + + /** + * setEventId. + **/ + public void setEventId(String eventId) { + this.eventId = eventId; + } + + + /** + * site. + * + * @return StreamingEventRow + **/ + public StreamingEventRow site(String site) { + this.site = site; + return this; + } + + /** + * Get site. + * @return site + **/ + @Schema(description = "") + public String getSite() { + return site; + } + + /** + * setSite. + **/ + public void setSite(String site) { + this.site = site; + } + + + /** + * accountId. + * + * @return StreamingEventRow + **/ + public StreamingEventRow accountId(String accountId) { + this.accountId = accountId; + return this; + } + + /** + * Get accountId. + * @return accountId + **/ + @Schema(description = "") + public String getAccountId() { + return accountId; + } + + /** + * setAccountId. + **/ + public void setAccountId(String accountId) { + this.accountId = accountId; + } + + + /** + * organizationId. + * + * @return StreamingEventRow + **/ + public StreamingEventRow organizationId(String organizationId) { + this.organizationId = organizationId; + return this; + } + + /** + * Get organizationId. + * @return organizationId + **/ + @Schema(description = "") + public String getOrganizationId() { + return organizationId; + } + + /** + * setOrganizationId. + **/ + public void setOrganizationId(String organizationId) { + this.organizationId = organizationId; + } + + + /** + * userId. + * + * @return StreamingEventRow + **/ + public StreamingEventRow userId(String userId) { + this.userId = userId; + return this; + } + + /** + * Get userId. + * @return userId + **/ + @Schema(description = "") + public String getUserId() { + return userId; + } + + /** + * setUserId. + **/ + public void setUserId(String userId) { + this.userId = userId; + } + + + /** + * integratorKey. + * + * @return StreamingEventRow + **/ + public StreamingEventRow integratorKey(String integratorKey) { + this.integratorKey = integratorKey; + return this; + } + + /** + * Get integratorKey. + * @return integratorKey + **/ + @Schema(description = "") + public String getIntegratorKey() { + return integratorKey; + } + + /** + * setIntegratorKey. + **/ + public void setIntegratorKey(String integratorKey) { + this.integratorKey = integratorKey; + } + + + /** + * userAgent. + * + * @return StreamingEventRow + **/ + public StreamingEventRow userAgent(String userAgent) { + this.userAgent = userAgent; + return this; + } + + /** + * Get userAgent. + * @return userAgent + **/ + @Schema(description = "") + public String getUserAgent() { + return userAgent; + } + + /** + * setUserAgent. + **/ + public void setUserAgent(String userAgent) { + this.userAgent = userAgent; + } + + + /** + * userAgentClientInfo. + * + * @return StreamingEventRow + **/ + public StreamingEventRow userAgentClientInfo(UserAgentClientInfo userAgentClientInfo) { + this.userAgentClientInfo = userAgentClientInfo; + return this; + } + + /** + * Get userAgentClientInfo. + * @return userAgentClientInfo + **/ + @Schema(description = "") + public UserAgentClientInfo getUserAgentClientInfo() { + return userAgentClientInfo; + } + + /** + * setUserAgentClientInfo. + **/ + public void setUserAgentClientInfo(UserAgentClientInfo userAgentClientInfo) { + this.userAgentClientInfo = userAgentClientInfo; + } + + + /** + * ipAddress. + * + * @return StreamingEventRow + **/ + public StreamingEventRow ipAddress(String ipAddress) { + this.ipAddress = ipAddress; + return this; + } + + /** + * Get ipAddress. + * @return ipAddress + **/ + @Schema(description = "") + public String getIpAddress() { + return ipAddress; + } + + /** + * setIpAddress. + **/ + public void setIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + } + + + /** + * ipAddressLocation. + * + * @return StreamingEventRow + **/ + public StreamingEventRow ipAddressLocation(IpAddressLocation ipAddressLocation) { + this.ipAddressLocation = ipAddressLocation; + return this; + } + + /** + * Get ipAddressLocation. + * @return ipAddressLocation + **/ + @Schema(description = "") + public IpAddressLocation getIpAddressLocation() { + return ipAddressLocation; + } + + /** + * setIpAddressLocation. + **/ + public void setIpAddressLocation(IpAddressLocation ipAddressLocation) { + this.ipAddressLocation = ipAddressLocation; + } + + + /** + * object. + * + * @return StreamingEventRow + **/ + public StreamingEventRow object(String object) { + this.object = object; + return this; + } + + /** + * Get object. + * @return object + **/ + @Schema(description = "") + public String getObject() { + return object; + } + + /** + * setObject. + **/ + public void setObject(String object) { + this.object = object; + } + + + /** + * action. + * + * @return StreamingEventRow + **/ + public StreamingEventRow action(String action) { + this.action = action; + return this; + } + + /** + * Get action. + * @return action + **/ + @Schema(description = "") + public String getAction() { + return action; + } + + /** + * setAction. + **/ + public void setAction(String action) { + this.action = action; + } + + + /** + * property. + * + * @return StreamingEventRow + **/ + public StreamingEventRow property(String property) { + this.property = property; + return this; + } + + /** + * Get property. + * @return property + **/ + @Schema(description = "") + public String getProperty() { + return property; + } + + /** + * setProperty. + **/ + public void setProperty(String property) { + this.property = property; + } + + + /** + * field. + * + * @return StreamingEventRow + **/ + public StreamingEventRow field(String field) { + this.field = field; + return this; + } + + /** + * Get field. + * @return field + **/ + @Schema(description = "") + public String getField() { + return field; + } + + /** + * setField. + **/ + public void setField(String field) { + this.field = field; + } + + + /** + * result. + * + * @return StreamingEventRow + **/ + public StreamingEventRow result(String result) { + this.result = result; + return this; + } + + /** + * Get result. + * @return result + **/ + @Schema(description = "") + public String getResult() { + return result; + } + + /** + * setResult. + **/ + public void setResult(String result) { + this.result = result; + } + + + /** + * source. + * + * @return StreamingEventRow + **/ + public StreamingEventRow source(String source) { + this.source = source; + return this; + } + + /** + * Get source. + * @return source + **/ + @Schema(description = "") + public String getSource() { + return source; + } + + /** + * setSource. + **/ + public void setSource(String source) { + this.source = source; + } + + + /** + * isUserMemberOfDomain. + * + * @return StreamingEventRow + **/ + public StreamingEventRow isUserMemberOfDomain(Boolean isUserMemberOfDomain) { + this.isUserMemberOfDomain = isUserMemberOfDomain; + return this; + } + + /** + * Get isUserMemberOfDomain. + * @return isUserMemberOfDomain + **/ + @Schema(description = "") + public Boolean isIsUserMemberOfDomain() { + return isUserMemberOfDomain; + } + + /** + * setIsUserMemberOfDomain. + **/ + public void setIsUserMemberOfDomain(Boolean isUserMemberOfDomain) { + this.isUserMemberOfDomain = isUserMemberOfDomain; + } + + + /** + * referencedUserIsMemberOfDomain. + * + * @return StreamingEventRow + **/ + public StreamingEventRow referencedUserIsMemberOfDomain(Boolean referencedUserIsMemberOfDomain) { + this.referencedUserIsMemberOfDomain = referencedUserIsMemberOfDomain; + return this; + } + + /** + * Get referencedUserIsMemberOfDomain. + * @return referencedUserIsMemberOfDomain + **/ + @Schema(description = "") + public Boolean isReferencedUserIsMemberOfDomain() { + return referencedUserIsMemberOfDomain; + } + + /** + * setReferencedUserIsMemberOfDomain. + **/ + public void setReferencedUserIsMemberOfDomain(Boolean referencedUserIsMemberOfDomain) { + this.referencedUserIsMemberOfDomain = referencedUserIsMemberOfDomain; + } + + + /** + * referencedUserId. + * + * @return StreamingEventRow + **/ + public StreamingEventRow referencedUserId(String referencedUserId) { + this.referencedUserId = referencedUserId; + return this; + } + + /** + * Get referencedUserId. + * @return referencedUserId + **/ + @Schema(description = "") + public String getReferencedUserId() { + return referencedUserId; + } + + /** + * setReferencedUserId. + **/ + public void setReferencedUserId(String referencedUserId) { + this.referencedUserId = referencedUserId; + } + + + /** + * proxyStatus. + * + * @return StreamingEventRow + **/ + public StreamingEventRow proxyStatus(String proxyStatus) { + this.proxyStatus = proxyStatus; + return this; + } + + /** + * Get proxyStatus. + * @return proxyStatus + **/ + @Schema(description = "") + public String getProxyStatus() { + return proxyStatus; + } + + /** + * setProxyStatus. + **/ + public void setProxyStatus(String proxyStatus) { + this.proxyStatus = proxyStatus; + } + + + /** + * proxyType. + * + * @return StreamingEventRow + **/ + public StreamingEventRow proxyType(String proxyType) { + this.proxyType = proxyType; + return this; + } + + /** + * Get proxyType. + * @return proxyType + **/ + @Schema(description = "") + public String getProxyType() { + return proxyType; + } + + /** + * setProxyType. + **/ + public void setProxyType(String proxyType) { + this.proxyType = proxyType; + } + + + /** + * proxyLevel. + * + * @return StreamingEventRow + **/ + public StreamingEventRow proxyLevel(String proxyLevel) { + this.proxyLevel = proxyLevel; + return this; + } + + /** + * Get proxyLevel. + * @return proxyLevel + **/ + @Schema(description = "") + public String getProxyLevel() { + return proxyLevel; + } + + /** + * setProxyLevel. + **/ + public void setProxyLevel(String proxyLevel) { + this.proxyLevel = proxyLevel; + } + + + /** + * latitude. + * + * @return StreamingEventRow + **/ + public StreamingEventRow latitude(Double latitude) { + this.latitude = latitude; + return this; + } + + /** + * Get latitude. + * @return latitude + **/ + @Schema(description = "") + public Double getLatitude() { + return latitude; + } + + /** + * setLatitude. + **/ + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + + /** + * longitude. + * + * @return StreamingEventRow + **/ + public StreamingEventRow longitude(Double longitude) { + this.longitude = longitude; + return this; + } + + /** + * Get longitude. + * @return longitude + **/ + @Schema(description = "") + public Double getLongitude() { + return longitude; + } + + /** + * setLongitude. + **/ + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + + /** + * city. + * + * @return StreamingEventRow + **/ + public StreamingEventRow city(String city) { + this.city = city; + return this; + } + + /** + * Get city. + * @return city + **/ + @Schema(description = "") + public String getCity() { + return city; + } + + /** + * setCity. + **/ + public void setCity(String city) { + this.city = city; + } + + + /** + * state. + * + * @return StreamingEventRow + **/ + public StreamingEventRow state(String state) { + this.state = state; + return this; + } + + /** + * Get state. + * @return state + **/ + @Schema(description = "") + public String getState() { + return state; + } + + /** + * setState. + **/ + public void setState(String state) { + this.state = state; + } + + + /** + * country. + * + * @return StreamingEventRow + **/ + public StreamingEventRow country(String country) { + this.country = country; + return this; + } + + /** + * Get country. + * @return country + **/ + @Schema(description = "") + public String getCountry() { + return country; + } + + /** + * setCountry. + **/ + public void setCountry(String country) { + this.country = country; + } + + + /** + * device. + * + * @return StreamingEventRow + **/ + public StreamingEventRow device(String device) { + this.device = device; + return this; + } + + /** + * Get device. + * @return device + **/ + @Schema(description = "") + public String getDevice() { + return device; + } + + /** + * setDevice. + **/ + public void setDevice(String device) { + this.device = device; + } + + + /** + * browser. + * + * @return StreamingEventRow + **/ + public StreamingEventRow browser(String browser) { + this.browser = browser; + return this; + } + + /** + * Get browser. + * @return browser + **/ + @Schema(description = "") + public String getBrowser() { + return browser; + } + + /** + * setBrowser. + **/ + public void setBrowser(String browser) { + this.browser = browser; + } + + + /** + * os. + * + * @return StreamingEventRow + **/ + public StreamingEventRow os(String os) { + this.os = os; + return this; + } + + /** + * Get os. + * @return os + **/ + @Schema(description = "") + public String getOs() { + return os; + } + + /** + * setOs. + **/ + public void setOs(String os) { + this.os = os; + } + + + /** + * affectedUserId. + * + * @return StreamingEventRow + **/ + public StreamingEventRow affectedUserId(String affectedUserId) { + this.affectedUserId = affectedUserId; + return this; + } + + /** + * Get affectedUserId. + * @return affectedUserId + **/ + @Schema(description = "") + public String getAffectedUserId() { + return affectedUserId; + } + + /** + * setAffectedUserId. + **/ + public void setAffectedUserId(String affectedUserId) { + this.affectedUserId = affectedUserId; + } + + + /** + * affectedUserIsMemberOfDomain. + * + * @return StreamingEventRow + **/ + public StreamingEventRow affectedUserIsMemberOfDomain(Boolean affectedUserIsMemberOfDomain) { + this.affectedUserIsMemberOfDomain = affectedUserIsMemberOfDomain; + return this; + } + + /** + * Get affectedUserIsMemberOfDomain. + * @return affectedUserIsMemberOfDomain + **/ + @Schema(description = "") + public Boolean isAffectedUserIsMemberOfDomain() { + return affectedUserIsMemberOfDomain; + } + + /** + * setAffectedUserIsMemberOfDomain. + **/ + public void setAffectedUserIsMemberOfDomain(Boolean affectedUserIsMemberOfDomain) { + this.affectedUserIsMemberOfDomain = affectedUserIsMemberOfDomain; + } + + + /** + * data. + * + * @return StreamingEventRow + **/ + public StreamingEventRow data(java.util.Map data) { + this.data = data; + return this; + } + + /** + * putDataItem. + * + * @return StreamingEventRow + **/ + public StreamingEventRow putDataItem(String key, Object dataItem) { + if (this.data == null) { + this.data = new java.util.HashMap<>(); + } + this.data.put(key, dataItem); + return this; + } + + /** + * Get data. + * @return data + **/ + @Schema(description = "") + public java.util.Map getData() { + return data; + } + + /** + * setData. + **/ + public void setData(java.util.Map data) { + this.data = data; + } + + + /** + * Compares objects. + * + * @return true or false depending on comparison result. + */ + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + StreamingEventRow streamingEventRow = (StreamingEventRow) o; + return Objects.equals(this.timestamp, streamingEventRow.timestamp) && + Objects.equals(this.eventId, streamingEventRow.eventId) && + Objects.equals(this.site, streamingEventRow.site) && + Objects.equals(this.accountId, streamingEventRow.accountId) && + Objects.equals(this.organizationId, streamingEventRow.organizationId) && + Objects.equals(this.userId, streamingEventRow.userId) && + Objects.equals(this.integratorKey, streamingEventRow.integratorKey) && + Objects.equals(this.userAgent, streamingEventRow.userAgent) && + Objects.equals(this.userAgentClientInfo, streamingEventRow.userAgentClientInfo) && + Objects.equals(this.ipAddress, streamingEventRow.ipAddress) && + Objects.equals(this.ipAddressLocation, streamingEventRow.ipAddressLocation) && + Objects.equals(this.object, streamingEventRow.object) && + Objects.equals(this.action, streamingEventRow.action) && + Objects.equals(this.property, streamingEventRow.property) && + Objects.equals(this.field, streamingEventRow.field) && + Objects.equals(this.result, streamingEventRow.result) && + Objects.equals(this.source, streamingEventRow.source) && + Objects.equals(this.isUserMemberOfDomain, streamingEventRow.isUserMemberOfDomain) && + Objects.equals(this.referencedUserIsMemberOfDomain, streamingEventRow.referencedUserIsMemberOfDomain) && + Objects.equals(this.referencedUserId, streamingEventRow.referencedUserId) && + Objects.equals(this.proxyStatus, streamingEventRow.proxyStatus) && + Objects.equals(this.proxyType, streamingEventRow.proxyType) && + Objects.equals(this.proxyLevel, streamingEventRow.proxyLevel) && + Objects.equals(this.latitude, streamingEventRow.latitude) && + Objects.equals(this.longitude, streamingEventRow.longitude) && + Objects.equals(this.city, streamingEventRow.city) && + Objects.equals(this.state, streamingEventRow.state) && + Objects.equals(this.country, streamingEventRow.country) && + Objects.equals(this.device, streamingEventRow.device) && + Objects.equals(this.browser, streamingEventRow.browser) && + Objects.equals(this.os, streamingEventRow.os) && + Objects.equals(this.affectedUserId, streamingEventRow.affectedUserId) && + Objects.equals(this.affectedUserIsMemberOfDomain, streamingEventRow.affectedUserIsMemberOfDomain) && + Objects.equals(this.data, streamingEventRow.data); + } + + /** + * Returns the HashCode. + */ + @Override + public int hashCode() { + return Objects.hash(timestamp, eventId, site, accountId, organizationId, userId, integratorKey, userAgent, userAgentClientInfo, ipAddress, ipAddressLocation, object, action, property, field, result, source, isUserMemberOfDomain, referencedUserIsMemberOfDomain, referencedUserId, proxyStatus, proxyType, proxyLevel, latitude, longitude, city, state, country, device, browser, os, affectedUserId, affectedUserIsMemberOfDomain, data); + } + + + /** + * Converts the given object to string. + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class StreamingEventRow {\n"); + + sb.append(" timestamp: ").append(toIndentedString(timestamp)).append("\n"); + sb.append(" eventId: ").append(toIndentedString(eventId)).append("\n"); + sb.append(" site: ").append(toIndentedString(site)).append("\n"); + sb.append(" accountId: ").append(toIndentedString(accountId)).append("\n"); + sb.append(" organizationId: ").append(toIndentedString(organizationId)).append("\n"); + sb.append(" userId: ").append(toIndentedString(userId)).append("\n"); + sb.append(" integratorKey: ").append(toIndentedString(integratorKey)).append("\n"); + sb.append(" userAgent: ").append(toIndentedString(userAgent)).append("\n"); + sb.append(" userAgentClientInfo: ").append(toIndentedString(userAgentClientInfo)).append("\n"); + sb.append(" ipAddress: ").append(toIndentedString(ipAddress)).append("\n"); + sb.append(" ipAddressLocation: ").append(toIndentedString(ipAddressLocation)).append("\n"); + sb.append(" object: ").append(toIndentedString(object)).append("\n"); + sb.append(" action: ").append(toIndentedString(action)).append("\n"); + sb.append(" property: ").append(toIndentedString(property)).append("\n"); + sb.append(" field: ").append(toIndentedString(field)).append("\n"); + sb.append(" result: ").append(toIndentedString(result)).append("\n"); + sb.append(" source: ").append(toIndentedString(source)).append("\n"); + sb.append(" isUserMemberOfDomain: ").append(toIndentedString(isUserMemberOfDomain)).append("\n"); + sb.append(" referencedUserIsMemberOfDomain: ").append(toIndentedString(referencedUserIsMemberOfDomain)).append("\n"); + sb.append(" referencedUserId: ").append(toIndentedString(referencedUserId)).append("\n"); + sb.append(" proxyStatus: ").append(toIndentedString(proxyStatus)).append("\n"); + sb.append(" proxyType: ").append(toIndentedString(proxyType)).append("\n"); + sb.append(" proxyLevel: ").append(toIndentedString(proxyLevel)).append("\n"); + sb.append(" latitude: ").append(toIndentedString(latitude)).append("\n"); + sb.append(" longitude: ").append(toIndentedString(longitude)).append("\n"); + sb.append(" city: ").append(toIndentedString(city)).append("\n"); + sb.append(" state: ").append(toIndentedString(state)).append("\n"); + sb.append(" country: ").append(toIndentedString(country)).append("\n"); + sb.append(" device: ").append(toIndentedString(device)).append("\n"); + sb.append(" browser: ").append(toIndentedString(browser)).append("\n"); + sb.append(" os: ").append(toIndentedString(os)).append("\n"); + sb.append(" affectedUserId: ").append(toIndentedString(affectedUserId)).append("\n"); + sb.append(" affectedUserIsMemberOfDomain: ").append(toIndentedString(affectedUserIsMemberOfDomain)).append("\n"); + sb.append(" data: ").append(toIndentedString(data)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/com/docusign/monitor/model/UserAgentClientInfo.java b/src/main/java/com/docusign/monitor/model/UserAgentClientInfo.java new file mode 100644 index 0000000..8395eb2 --- /dev/null +++ b/src/main/java/com/docusign/monitor/model/UserAgentClientInfo.java @@ -0,0 +1,168 @@ +package com.docusign.monitor.model; + +import java.util.Objects; +import java.util.Arrays; +import com.docusign.monitor.model.Browser; +import com.docusign.monitor.model.Device; +import com.docusign.monitor.model.Os; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import io.swagger.v3.oas.annotations.media.Schema; +import java.io.Serializable; + +/** + * UserAgentClientInfo. + * + */ + +public class UserAgentClientInfo implements Serializable { + private static final long serialVersionUID = 1L; + + @JsonProperty("browser") + private Browser browser = null; + + @JsonProperty("device") + private Device device = null; + + @JsonProperty("os") + private Os os = null; + + + /** + * browser. + * + * @return UserAgentClientInfo + **/ + public UserAgentClientInfo browser(Browser browser) { + this.browser = browser; + return this; + } + + /** + * Get browser. + * @return browser + **/ + @Schema(description = "") + public Browser getBrowser() { + return browser; + } + + /** + * setBrowser. + **/ + public void setBrowser(Browser browser) { + this.browser = browser; + } + + + /** + * device. + * + * @return UserAgentClientInfo + **/ + public UserAgentClientInfo device(Device device) { + this.device = device; + return this; + } + + /** + * Get device. + * @return device + **/ + @Schema(description = "") + public Device getDevice() { + return device; + } + + /** + * setDevice. + **/ + public void setDevice(Device device) { + this.device = device; + } + + + /** + * os. + * + * @return UserAgentClientInfo + **/ + public UserAgentClientInfo os(Os os) { + this.os = os; + return this; + } + + /** + * Get os. + * @return os + **/ + @Schema(description = "") + public Os getOs() { + return os; + } + + /** + * setOs. + **/ + public void setOs(Os os) { + this.os = os; + } + + + /** + * Compares objects. + * + * @return true or false depending on comparison result. + */ + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + UserAgentClientInfo userAgentClientInfo = (UserAgentClientInfo) o; + return Objects.equals(this.browser, userAgentClientInfo.browser) && + Objects.equals(this.device, userAgentClientInfo.device) && + Objects.equals(this.os, userAgentClientInfo.os); + } + + /** + * Returns the HashCode. + */ + @Override + public int hashCode() { + return Objects.hash(browser, device, os); + } + + + /** + * Converts the given object to string. + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class UserAgentClientInfo {\n"); + + sb.append(" browser: ").append(toIndentedString(browser)).append("\n"); + sb.append(" device: ").append(toIndentedString(device)).append("\n"); + sb.append(" os: ").append(toIndentedString(os)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/main/java/com/docusign/monitor/model/Version.java b/src/main/java/com/docusign/monitor/model/Version.java new file mode 100644 index 0000000..b643e88 --- /dev/null +++ b/src/main/java/com/docusign/monitor/model/Version.java @@ -0,0 +1,165 @@ +package com.docusign.monitor.model; + +import java.util.Objects; +import java.util.Arrays; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import io.swagger.v3.oas.annotations.media.Schema; +import java.io.Serializable; + +/** + * Version. + * + */ + +public class Version implements Serializable { + private static final long serialVersionUID = 1L; + + @JsonProperty("major") + private String major = null; + + @JsonProperty("minor") + private String minor = null; + + @JsonProperty("patch") + private String patch = null; + + + /** + * major. + * + * @return Version + **/ + public Version major(String major) { + this.major = major; + return this; + } + + /** + * Get major. + * @return major + **/ + @Schema(description = "") + public String getMajor() { + return major; + } + + /** + * setMajor. + **/ + public void setMajor(String major) { + this.major = major; + } + + + /** + * minor. + * + * @return Version + **/ + public Version minor(String minor) { + this.minor = minor; + return this; + } + + /** + * Get minor. + * @return minor + **/ + @Schema(description = "") + public String getMinor() { + return minor; + } + + /** + * setMinor. + **/ + public void setMinor(String minor) { + this.minor = minor; + } + + + /** + * patch. + * + * @return Version + **/ + public Version patch(String patch) { + this.patch = patch; + return this; + } + + /** + * Get patch. + * @return patch + **/ + @Schema(description = "") + public String getPatch() { + return patch; + } + + /** + * setPatch. + **/ + public void setPatch(String patch) { + this.patch = patch; + } + + + /** + * Compares objects. + * + * @return true or false depending on comparison result. + */ + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Version version = (Version) o; + return Objects.equals(this.major, version.major) && + Objects.equals(this.minor, version.minor) && + Objects.equals(this.patch, version.patch); + } + + /** + * Returns the HashCode. + */ + @Override + public int hashCode() { + return Objects.hash(major, minor, patch); + } + + + /** + * Converts the given object to string. + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Version {\n"); + + sb.append(" major: ").append(toIndentedString(major)).append("\n"); + sb.append(" minor: ").append(toIndentedString(minor)).append("\n"); + sb.append(" patch: ").append(toIndentedString(patch)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/src/test/java/SdkUnitTests.java b/src/test/java/SdkUnitTests.java index 11fe25f..51c2259 100644 --- a/src/test/java/SdkUnitTests.java +++ b/src/test/java/SdkUnitTests.java @@ -3,13 +3,16 @@ import com.docusign.monitor.client.auth.OAuth; import com.docusign.monitor.client.auth.OAuth.UserInfo; -import com.docusign.monitor.model.CursoredResult; +import com.docusign.monitor.model.StreamResponse; import org.junit.*; import org.junit.runners.MethodSorters; //import java.awt.*; //import java.net.URI; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; +import java.util.UUID; import com.migcomponents.migbase64.Base64; @@ -29,7 +32,7 @@ public class SdkUnitTests { //private static final String ClientSecret = System.getenv("CLIENT_SECRET"); //private static final String RedirectURI = System.getenv("REDIRECT_URI"); - private static final String BaseUrl = ApiClient.DEMO_REST_BASEPATH; + private static final String BaseUrl = "https://api-d.docusign.com"; //private static final String OAuthBaseUrl = OAuth.DEMO_OAUTH_BASEPATH; private static final byte[] privateKeyBytes = Base64.decode(System.getenv("PRIVATE_KEY")); // JUnit 4.12 runs test cases in parallel, so the envelope ID needs to be initiated as well. @@ -57,6 +60,7 @@ public void tearDown() { public void JWTLoginTest() { System.out.println("\nJWTLoginTest:\n" + "==========================================="); ApiClient apiClient = new ApiClient(BaseUrl); + apiClient.setOAuthBasePath(OAuth.DEMO_OAUTH_BASEPATH); //String currentDir = System.getenv("user.dir"); try { @@ -95,6 +99,7 @@ public void JWTLoginTest() { public void AuthorizationCodeLoginTest() { System.out.println("\nAuthorizationCodeLoginTest:\n" + "==========================================="); ApiClient apiClient = new ApiClient(BaseUrl); + apiClient.setOAuthBasePath(OAuth.DEMO_OAUTH_BASEPATH); try { // after successful login you should compare the value of URI decoded "state" query param // with the one you create here; they should match. @@ -175,6 +180,7 @@ public void ImplicitLoginTest() { public void GetStreamTest() { System.out.println("\nGetStreamTest:\n" + "==========================================="); ApiClient apiClient = new ApiClient(BaseUrl); + apiClient.setOAuthBasePath(OAuth.DEMO_OAUTH_BASEPATH); //String currentDir = System.getProperty("user.dir"); try { @@ -205,13 +211,24 @@ public void GetStreamTest() { Configuration.setDefaultApiClient(apiClient); - DataSetApi dataSetApi = new DataSetApi(); - String dataSetName = "monitor"; - String version = "2.0"; - CursoredResult cursoredResult = dataSetApi.getStream(version, dataSetName); - Assert.assertNotNull(cursoredResult.getData()); - - System.out.println("CursoredResult - first row: " + cursoredResult.getData().get(0)); + String organizationId = null; + for (OAuth.Account account : userInfo.getAccounts()) { + if (account.getOrganization() != null && account.getOrganization().getOrganizationId() != null) { + organizationId = account.getOrganization().getOrganizationId(); + break; + } + } + Assert.assertNotNull(organizationId); + + DocuMonitorApi docuMonitorApi = new DocuMonitorApi(); + DocuMonitorApi.StreamOptions streamOptions = docuMonitorApi.new StreamOptions(); + streamOptions.setCursor(Instant.now().minus(24, ChronoUnit.HOURS).truncatedTo(ChronoUnit.SECONDS).toString()); + streamOptions.setLimit(100); + StreamResponse streamResponse = docuMonitorApi.stream(UUID.fromString(organizationId), streamOptions); + Assert.assertNotNull(streamResponse); + Assert.assertNotNull(streamResponse.getEndCursor()); + + System.out.println("StreamResponse end cursor: " + streamResponse.getEndCursor()); } catch (ApiException ex) { Assert.fail("ApiException: " + ex.getLocalizedMessage()); } catch (Exception e) { @@ -219,4 +236,4 @@ public void GetStreamTest() { Assert.fail("Exception: " + e.getLocalizedMessage()); } } -} \ No newline at end of file +}