diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ae7115..622b0e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## v8.0.1 + +- We’ve removed the direct constructors for `TenantSecurityClient` and replaced them with a builder-based API. The static TenantSecurityClient.create method is still provided for convenience. +- TenantSecurityClient now enforces HTTPS connections to the TSP by default. You can opt out of this restriction using the new `TenantSecurityClient.Builder`, using `allowInsecureHttp(true)`. This should only be done in the case of testing. + +## v8.0.0 + +- Accidental release. Incomplete. Use 8.0.1 instead. + ## v7.2.3 - No code change, changed publishing to new sonatype. diff --git a/examples/README.md b/examples/README.md index 7cd06ed..e311d24 100644 --- a/examples/README.md +++ b/examples/README.md @@ -20,11 +20,11 @@ have included this configuration in the repository as a convenience. Also note t created in IronCore's staging infrastructure. The following command will get a TSP and LD running together on your computer with the provided configuration. -The `docker-compose` command will pull both container images, then start them up together on a subnetwork, so they can +The `docker compose` command will pull both container images, then start them up together on a subnetwork, so they can communicate with each other. ```bash -docker-compose -f docker-compose.yml up +docker compose -f docker-compose.yml up ``` The TSP will be listening locally on port 32804. diff --git a/examples/large-documents/pom.xml b/examples/large-documents/pom.xml index 078652b..ccdd1d1 100644 --- a/examples/large-documents/pom.xml +++ b/examples/large-documents/pom.xml @@ -29,7 +29,7 @@ com.ironcorelabs tenant-security-java - 4.0.1 + 8.0.1 com.google.guava diff --git a/examples/large-documents/src/main/java/com/ironcorelabs/large/LargeDocuments.java b/examples/large-documents/src/main/java/com/ironcorelabs/large/LargeDocuments.java index 7c390ec..6eb3ba8 100644 --- a/examples/large-documents/src/main/java/com/ironcorelabs/large/LargeDocuments.java +++ b/examples/large-documents/src/main/java/com/ironcorelabs/large/LargeDocuments.java @@ -40,7 +40,9 @@ public static void main(String[] args) throws Exception { // Initialize the client with a Tenant Security Proxy domain and API key. // Typically this would be done once when the application or service initializes - TenantSecurityClient client = TenantSecurityClient.create("http://localhost:32804", API_KEY).get(); + TenantSecurityClient client = + new TenantSecurityClient.Builder("http://localhost:32804", API_KEY) + .allowInsecureHttp(true).build(); // Create metadata used to associate this document to a tenant, name the // document, and identify the service or user making the call @@ -64,7 +66,8 @@ public static void main(String[] args) throws Exception { System.out.println("Writing encrypted files to: " + tmpFileDir); ObjectMapper objectMapper = new ObjectMapper(); - BigDoc sourceObj = objectMapper.readValue(new File("./resources/" + filename), BigDoc.class); + BigDoc sourceObj = + objectMapper.readValue(new File("./resources/" + filename), BigDoc.class); // Reduce the document to a map of all the sub documents to be encrypted with // the same key @@ -115,14 +118,17 @@ public static void main(String[] args) throws Exception { String subDocId2 = "4e57e8bd-d88a-4083-9fac-05a635110e2a"; // Read the two files out first - byte[] encryptedFile1 = Files.readAllBytes(Paths.get(tmpFileDir.toString(), subDocId1 + ".enc")); - byte[] encryptedFile2 = Files.readAllBytes(Paths.get(tmpFileDir.toString(), subDocId2 + ".enc")); + byte[] encryptedFile1 = + Files.readAllBytes(Paths.get(tmpFileDir.toString(), subDocId1 + ".enc")); + byte[] encryptedFile2 = + Files.readAllBytes(Paths.get(tmpFileDir.toString(), subDocId2 + ".enc")); // In a DB situation this edek could be stored with the large doc (if sub docs // are only decrypted in that context) or it could be stored alongside each // sub-document. In the latter case you make it harder to accidentally // cryptoshred data by de-syncing edeks at the cost of row size - String edek = new String(Files.readAllBytes(Paths.get(tmpFileDir.toString(), filename + ".edek"))); + String edek = new String( + Files.readAllBytes(Paths.get(tmpFileDir.toString(), filename + ".edek"))); // each of the documents could be individually decrypted with their own calls, // but by combining them into one structure we ensure we only make one call to @@ -133,15 +139,18 @@ public static void main(String[] args) throws Exception { EncryptedDocument encryptedPartialBigDoc = new EncryptedDocument(encryptedPartDocMap, edek); // Decrypt the two subdocuments - PlaintextDocument decryptedPartialBigDoc = client.decrypt(encryptedPartialBigDoc, metadata).get(); + PlaintextDocument decryptedPartialBigDoc = + client.decrypt(encryptedPartialBigDoc, metadata).get(); // Turn the decrypted bytes back into objects - SubDoc reSubDoc1 = objectMapper - .readValue(new String(decryptedPartialBigDoc.getDecryptedFields().get(subDocId1)), SubDoc.class); - SubDoc reSubDoc2 = objectMapper - .readValue(new String(decryptedPartialBigDoc.getDecryptedFields().get(subDocId2)), SubDoc.class); + SubDoc reSubDoc1 = objectMapper.readValue( + new String(decryptedPartialBigDoc.getDecryptedFields().get(subDocId1)), + SubDoc.class); + SubDoc reSubDoc2 = objectMapper.readValue( + new String(decryptedPartialBigDoc.getDecryptedFields().get(subDocId2)), + SubDoc.class); // just so we can write it out nicely - BigDoc rePartialBigDoc = new BigDoc("x", "x", "x", new SubDoc[] { reSubDoc1, reSubDoc2 }); + BigDoc rePartialBigDoc = new BigDoc("x", "x", "x", new SubDoc[] {reSubDoc1, reSubDoc2}); // Write out the rehydrated docs as proof that things round tripped fine Files.write(Paths.get(tmpFileDir.toString(), "partial-large-document.json"), diff --git a/examples/logging-example/pom.xml b/examples/logging-example/pom.xml index 1079401..b809044 100644 --- a/examples/logging-example/pom.xml +++ b/examples/logging-example/pom.xml @@ -29,7 +29,7 @@ com.ironcorelabs tenant-security-java - 4.0.0 + 8.0.1 @@ -82,4 +82,4 @@ - \ No newline at end of file + diff --git a/examples/logging-example/src/main/java/com/ironcorelabs/logging/LoggingExample.java b/examples/logging-example/src/main/java/com/ironcorelabs/logging/LoggingExample.java index a76f2eb..bef5a59 100644 --- a/examples/logging-example/src/main/java/com/ironcorelabs/logging/LoggingExample.java +++ b/examples/logging-example/src/main/java/com/ironcorelabs/logging/LoggingExample.java @@ -28,7 +28,9 @@ public static void main(String[] args) throws Exception { // Initialize the client with a Tenant Security Proxy domain and API key. // Typically this would be done once when the application or service initializes - TenantSecurityClient client = TenantSecurityClient.create("http://localhost:32804", API_KEY).get(); + TenantSecurityClient client = + new TenantSecurityClient.Builder("http://localhost:32804", API_KEY).allowInsecureHttp(true) + .build(); // Example 1: logging a user-related event // @@ -38,8 +40,8 @@ public static void main(String[] args) throws Exception { Map otherData = new HashMap<>(); otherData.put("field1", "gumby"); otherData.put("field2", "gumby"); - EventMetadata metadata1 = new EventMetadata(TENANT_ID, "userId1", "PII", otherData, "Rq8675309", "127.0.0.1", - "userId1", System.currentTimeMillis()); + EventMetadata metadata1 = new EventMetadata(TENANT_ID, "userId1", "PII", otherData, "Rq8675309", + "127.0.0.1", "userId1", System.currentTimeMillis()); try { client.logSecurityEvent(UserEvent.LOGIN, metadata1).get(); System.out.println("Successfully logged user login event."); diff --git a/examples/rekey-example/pom.xml b/examples/rekey-example/pom.xml index b4402d1..54d45e4 100644 --- a/examples/rekey-example/pom.xml +++ b/examples/rekey-example/pom.xml @@ -28,7 +28,7 @@ com.ironcorelabs tenant-security-java - 4.1.0 + 8.0.1 @@ -80,4 +80,4 @@ - \ No newline at end of file + diff --git a/examples/rekey-example/src/main/java/com/ironcorelabs/rekey/RekeyExample.java b/examples/rekey-example/src/main/java/com/ironcorelabs/rekey/RekeyExample.java index 747d4c7..43f7e0e 100644 --- a/examples/rekey-example/src/main/java/com/ironcorelabs/rekey/RekeyExample.java +++ b/examples/rekey-example/src/main/java/com/ironcorelabs/rekey/RekeyExample.java @@ -2,6 +2,7 @@ import com.ironcorelabs.tenantsecurity.kms.v1.*; import com.ironcorelabs.tenantsecurity.kms.v1.exception.TenantSecurityException; +import com.ironcorelabs.tenantsecurity.utils.CompletableFutures; import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; @@ -12,11 +13,14 @@ /** * Three parts: * - *

Encrypt a customer record + *

+ * Encrypt a customer record * - *

Rekey the encrypted record to a new tenant + *

+ * Rekey the encrypted record to a new tenant * - *

Decrypt the encrypted record using the new tenant + *

+ * Decrypt the encrypted record using the new tenant */ public class RekeyExample { @@ -44,77 +48,69 @@ public static void main(String[] args) throws Exception { // Initialize the client with a Tenant Security Proxy domain and API key. // Typically this would be done once when the application or service initializes. - CompletableFuture rekeyedRoundtrip = - TenantSecurityClient.create(TSP_ADDR, API_KEY) - .thenCompose( - client -> { - try { - // - // Part 1: Encrypting a customer record - // - - // Create metadata used to associate this document to the first tenant, name the - // document, and identify the service or user making the call - DocumentMetadata metadata = - new DocumentMetadata(TENANT_ID, "serviceOrUserId", "PII"); - - // Create a map containing your data - Map custRecord = new HashMap<>(); - custRecord.put("ssn", "000-12-2345".getBytes("UTF-8")); - custRecord.put( - "address", "2825-519 Stone Creek Rd, Bozeman, MT 59715".getBytes("UTF-8")); - custRecord.put("name", "Jim Bridger".getBytes("UTF-8")); - - System.out.println("Encrypting using tenant " + TENANT_ID); - // Request a key from the KMS and use it to encrypt the document - CompletableFuture encryptedDocument = - client.encrypt(custRecord, metadata); - - // - // Part 2: Rekey the encrypted record to a new tenant - // - - final String NEW_TENANT_ID = "tenant-aws"; - - System.out.println("Rekeying to tenant " + NEW_TENANT_ID); - - CompletableFuture rekeyedDocument = - encryptedDocument.thenCompose( - // Rekey the document to `tenant-aws` using their primary config. The - // metadata's name and identifying information could also be changed at - // this time. - encrypted -> - client.rekeyEdek(encrypted.getEdek(), metadata, NEW_TENANT_ID) - .thenApply( - newDoc -> - new EncryptedDocument(encrypted.getEncryptedFields(), - newDoc) - )); - - - - // - // Part 3: Decrypt the encrypted record using the new tenant - // - - // Create new metadata for this document indicating that it was - // rekeyed to the second tenant. The name and identifying information - // could also be changed at this time. - DocumentMetadata newMetadata = - new DocumentMetadata(NEW_TENANT_ID, "serviceOrUserId", "PII"); - - System.out.println("Decrypting with tenant " + NEW_TENANT_ID); - - CompletableFuture decryptedDocument = - rekeyedDocument.thenCompose( - // Decrypt the document encrypted to `tenant-aws` - rekeyed -> client.decrypt(rekeyed, newMetadata)); - - return decryptedDocument; - } catch (Exception e) { - throw new CompletionException(e); - } - }); + CompletableFuture rekeyedRoundtrip = CompletableFutures.tryCatchNonFatal( + () -> new TenantSecurityClient.Builder(TSP_ADDR, API_KEY).allowInsecureHttp(true).build()) + .thenCompose(client -> { + try { + // + // Part 1: Encrypting a customer record + // + + // Create metadata used to associate this document to the first tenant, name the + // document, and identify the service or user making the call + DocumentMetadata metadata = new DocumentMetadata(TENANT_ID, "serviceOrUserId", "PII"); + + // Create a map containing your data + Map custRecord = new HashMap<>(); + custRecord.put("ssn", "000-12-2345".getBytes("UTF-8")); + custRecord.put("address", + "2825-519 Stone Creek Rd, Bozeman, MT 59715".getBytes("UTF-8")); + custRecord.put("name", "Jim Bridger".getBytes("UTF-8")); + + System.out.println("Encrypting using tenant " + TENANT_ID); + // Request a key from the KMS and use it to encrypt the document + CompletableFuture encryptedDocument = + client.encrypt(custRecord, metadata); + + // + // Part 2: Rekey the encrypted record to a new tenant + // + + final String NEW_TENANT_ID = "tenant-aws"; + + System.out.println("Rekeying to tenant " + NEW_TENANT_ID); + + CompletableFuture rekeyedDocument = encryptedDocument.thenCompose( + // Rekey the document to `tenant-aws` using their primary config. The + // metadata's name and identifying information could also be changed at + // this time. + encrypted -> client.rekeyEdek(encrypted.getEdek(), metadata, NEW_TENANT_ID) + .thenApply( + newDoc -> new EncryptedDocument(encrypted.getEncryptedFields(), newDoc))); + + + + // + // Part 3: Decrypt the encrypted record using the new tenant + // + + // Create new metadata for this document indicating that it was + // rekeyed to the second tenant. The name and identifying information + // could also be changed at this time. + DocumentMetadata newMetadata = + new DocumentMetadata(NEW_TENANT_ID, "serviceOrUserId", "PII"); + + System.out.println("Decrypting with tenant " + NEW_TENANT_ID); + + CompletableFuture decryptedDocument = rekeyedDocument.thenCompose( + // Decrypt the document encrypted to `tenant-aws` + rekeyed -> client.decrypt(rekeyed, newMetadata)); + + return decryptedDocument; + } catch (Exception e) { + throw new CompletionException(e); + } + }); try { // access decrypted fields @@ -122,9 +118,8 @@ public static void main(String[] args) throws Exception { System.out.println( "Decrypted SSN: " + new String(decryptedValuesMap.get("ssn"), StandardCharsets.UTF_8)); - System.out.println( - "Decrypted address: " - + new String(decryptedValuesMap.get("address"), StandardCharsets.UTF_8)); + System.out.println("Decrypted address: " + + new String(decryptedValuesMap.get("address"), StandardCharsets.UTF_8)); System.out.println( "Decrypted name: " + new String(decryptedValuesMap.get("name"), StandardCharsets.UTF_8)); } catch (ExecutionException e) { diff --git a/examples/simple-roundtrip/pom.xml b/examples/simple-roundtrip/pom.xml index 778d2db..634d535 100644 --- a/examples/simple-roundtrip/pom.xml +++ b/examples/simple-roundtrip/pom.xml @@ -29,7 +29,7 @@ com.ironcorelabs tenant-security-java - 4.0.0 + 8.0.1 @@ -82,4 +82,4 @@ - \ No newline at end of file + diff --git a/examples/simple-roundtrip/src/main/java/com/ironcorelabs/simple/SimpleRoundtrip.java b/examples/simple-roundtrip/src/main/java/com/ironcorelabs/simple/SimpleRoundtrip.java index 6a741c9..bfbdab6 100644 --- a/examples/simple-roundtrip/src/main/java/com/ironcorelabs/simple/SimpleRoundtrip.java +++ b/examples/simple-roundtrip/src/main/java/com/ironcorelabs/simple/SimpleRoundtrip.java @@ -2,7 +2,7 @@ import com.ironcorelabs.tenantsecurity.kms.v1.*; import com.ironcorelabs.tenantsecurity.kms.v1.exception.TenantSecurityException; - +import com.ironcorelabs.tenantsecurity.utils.CompletableFutures; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -63,39 +63,55 @@ public static void main(String[] args) throws Exception { CompletableFuture roundtrip = // Initialize the client with a Tenant Security Proxy domain and API key. // Typically this would be done once when the application or service initializes - TenantSecurityClient.create(TSP_ADDR, API_KEY).thenCompose(client -> { - - try { - return client.encrypt(custRecord, metadata) - .thenCompose(encryptedResults -> { - // persist the EDEK and encryptedDocument to your persistence layer - String edek = encryptedResults.getEdek(); - Map encryptedDocument = encryptedResults.getEncryptedFields(); - - // un-comment if you want to print out the encrypted data - //System.out.println("Encrypted SSN: " + new String(encryptedDocument.get("ssn"), StandardCharsets.UTF_8)); - //System.out.println("Encrypted address: " + new String(encryptedDocument.get("address"), StandardCharsets.UTF_8)); - //System.out.println("Encrypted name: " + new String(encryptedDocument.get("name"), StandardCharsets.UTF_8)); - - - // retrieve the EDEK and encryptedDocument from your persistence layer - EncryptedDocument retrievedEncryptedDocument = new EncryptedDocument(encryptedDocument, edek); - - // decrypt back into plaintext - return client.decrypt(encryptedResults, metadata); - }); - } catch (Exception e) { - throw new CompletionException(e); - } - }); + CompletableFutures + .tryCatchNonFatal(() -> new TenantSecurityClient.Builder(TSP_ADDR, API_KEY) + .allowInsecureHttp(true).build()) + .thenCompose(client -> { + try { + return client.encrypt(custRecord, metadata) + .thenCompose(encryptedResults -> { + // persist the EDEK and encryptedDocument to your + // persistence layer + String edek = encryptedResults.getEdek(); + Map encryptedDocument = + encryptedResults.getEncryptedFields(); + + // un-comment if you want to print out the encrypted + // data + // System.out.println("Encrypted SSN: " + new + // String(encryptedDocument.get("ssn"), + // StandardCharsets.UTF_8)); + // System.out.println("Encrypted address: " + new + // String(encryptedDocument.get("address"), + // StandardCharsets.UTF_8)); + // System.out.println("Encrypted name: " + new + // String(encryptedDocument.get("name"), + // StandardCharsets.UTF_8)); + + + // retrieve the EDEK and encryptedDocument from your + // persistence layer + EncryptedDocument retrievedEncryptedDocument = + new EncryptedDocument(encryptedDocument, edek); + + // decrypt back into plaintext + return client.decrypt(encryptedResults, metadata); + }); + } catch (Exception e) { + throw new CompletionException(e); + } + }); try { - // access decrypted fields + // access decrypted fields Map decryptedValuesMap = roundtrip.get().getDecryptedFields(); - System.out.println("Decrypted SSN: " + new String(decryptedValuesMap.get("ssn"), StandardCharsets.UTF_8)); - System.out.println("Decrypted address: " + new String(decryptedValuesMap.get("address"), StandardCharsets.UTF_8)); - System.out.println("Decrypted name: " + new String(decryptedValuesMap.get("name"), StandardCharsets.UTF_8)); + System.out.println("Decrypted SSN: " + + new String(decryptedValuesMap.get("ssn"), StandardCharsets.UTF_8)); + System.out.println("Decrypted address: " + + new String(decryptedValuesMap.get("address"), StandardCharsets.UTF_8)); + System.out.println("Decrypted name: " + + new String(decryptedValuesMap.get("name"), StandardCharsets.UTF_8)); } catch (ExecutionException e) { if (e.getCause() instanceof TenantSecurityException) { TenantSecurityException kmsError = (TenantSecurityException) e.getCause(); @@ -121,41 +137,57 @@ public static void main(String[] args) throws Exception { CompletableFuture roundtripFile = // Initialize the client with a Tenant Security Proxy domain and API key. // Typically this would be done once when the application or service initializes - TenantSecurityClient.create(TSP_ADDR, API_KEY).thenCompose(client -> { - - try { - return client.encrypt(toEncrypt, metadata) - .thenCompose(encryptedResults -> { - // write the encrypted file and the encrypted key to the filesystem - try { - Files.write(Paths.get(sourceFile + ".enc"), encryptedResults.getEncryptedFields().get("file")); - Files.write(Paths.get(sourceFile + ".edek"), encryptedResults.getEdek().getBytes(StandardCharsets.UTF_8)); - } catch (IOException e) { - throw new CompletionException(e); - } - - // some time later... read the file from the disk - try { - byte[] encryptedBytes = Files.readAllBytes(Paths.get(sourceFile + ".enc")); - byte[] encryptedDek = Files.readAllBytes(Paths.get(sourceFile + ".edek")); - - EncryptedDocument fileAndEdek = new EncryptedDocument(Collections.singletonMap("file", encryptedBytes), new String(encryptedDek, StandardCharsets.UTF_8)); - - // decrypt - return client.decrypt(fileAndEdek, metadata); - - } catch (IOException e) { - throw new CompletionException(e); - } - }); - } catch (Exception e) { - throw new CompletionException(e); - } - }); + CompletableFutures + .tryCatchNonFatal(() -> new TenantSecurityClient.Builder(TSP_ADDR, API_KEY) + .allowInsecureHttp(true).build()) + .thenCompose(client -> { + + try { + return client.encrypt(toEncrypt, metadata) + .thenCompose(encryptedResults -> { + // write the encrypted file and the encrypted key to the + // filesystem + try { + Files.write(Paths.get(sourceFile + ".enc"), + encryptedResults.getEncryptedFields() + .get("file")); + Files.write(Paths.get(sourceFile + ".edek"), + encryptedResults.getEdek() + .getBytes(StandardCharsets.UTF_8)); + } catch (IOException e) { + throw new CompletionException(e); + } + + // some time later... read the file from the disk + try { + byte[] encryptedBytes = Files.readAllBytes( + Paths.get(sourceFile + ".enc")); + byte[] encryptedDek = Files.readAllBytes( + Paths.get(sourceFile + ".edek")); + + EncryptedDocument fileAndEdek = + new EncryptedDocument( + Collections.singletonMap("file", + encryptedBytes), + new String(encryptedDek, + StandardCharsets.UTF_8)); + + // decrypt + return client.decrypt(fileAndEdek, metadata); + + } catch (IOException e) { + throw new CompletionException(e); + } + }); + } catch (Exception e) { + throw new CompletionException(e); + } + }); try { // write the decrypted file back to the filesystem - Files.write(Paths.get("decrypted.jpg"), roundtripFile.get().getDecryptedFields().get("file")); + Files.write(Paths.get("decrypted.jpg"), + roundtripFile.get().getDecryptedFields().get("file")); } catch (ExecutionException e) { if (e.getCause() instanceof TenantSecurityException) { TenantSecurityException kmsError = (TenantSecurityException) e.getCause(); diff --git a/pom.xml b/pom.xml index 14442d1..2b997f8 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ com.ironcorelabs tenant-security-java jar - 7.2.3 + 8.0.1 tenant-security-java https://ironcorelabs.com/docs Java client library for the IronCore Labs Tenant Security Proxy. @@ -63,7 +63,7 @@ com.google.http-client - google-http-client-jackson2 + google-http-client-gson com.google.http-client @@ -144,10 +144,10 @@ maven-compiler-plugin 3.8.1 - 11 - 11 - 11 - 11 + 17 + 17 + 17 + 17 -Xlint:unchecked @@ -184,7 +184,7 @@ true - com.google.http-client:google-http-client-jackson2 + com.google.http-client:google-http-client-gson com.google.http-client:google-http-client-apache-v2 com.google.guava:guava com.google.protobuf:protobuf-java @@ -197,7 +197,7 @@ io.grpc:grpc-context io.grpc:grpc-api io.opencensus:opencensus-contrib-http-util - com.fasterxml.jackson.core:jackson-core + com.google.code.gson:gson diff --git a/src/main/java/com/ironcorelabs/tenantsecurity/kms/v1/TenantSecurityClient.java b/src/main/java/com/ironcorelabs/tenantsecurity/kms/v1/TenantSecurityClient.java index 4b3dbf0..0074447 100644 --- a/src/main/java/com/ironcorelabs/tenantsecurity/kms/v1/TenantSecurityClient.java +++ b/src/main/java/com/ironcorelabs/tenantsecurity/kms/v1/TenantSecurityClient.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.net.MalformedURLException; import java.net.URL; import java.security.SecureRandom; import java.security.Security; @@ -37,134 +38,169 @@ public final class TenantSecurityClient implements Closeable { private DeterministicTenantSecurityClient deterministicClient; - /** - * Default size of web request thread pool. Defaults to 25. - */ - public static int DEFAULT_REQUEST_THREADPOOL_SIZE = 25; - - /** - * Default size of the threadpool used for AES encryptions/decryptions. Defaults to the number of - * cores on the machine being run on. - */ - public static int DEFAULT_AES_THREADPOOL_SIZE = Runtime.getRuntime().availableProcessors(); + private TenantSecurityClient(Builder builder) throws Exception { + // Validate domain + TenantSecurityClient.checkUrlForm(builder.tspDomain, builder.allowInsecureHttp); - /** - * Default timeout in ms for the connection to the TSP. - */ - public static int DEFAULT_TIMEOUT_MS = 20000; - - /** - * Constructor for TenantSecurityClient class that uses the SecureRandom NativePRNGNonBlocking - * instance for random number generation. - * - * @param tspDomain Domain where the Tenant Security Proxy is running. - * @param apiKey Key to use for requests to the Tenant Security Proxy. - * @throws Exception If the provided domain is invalid. - */ - public TenantSecurityClient(String tspDomain, String apiKey) throws Exception { - this(tspDomain, apiKey, DEFAULT_REQUEST_THREADPOOL_SIZE, DEFAULT_AES_THREADPOOL_SIZE, - SecureRandom.getInstance("NativePRNGNonBlocking")); - } - - /** - * Constructor for TenantSecurityClient class that allows call to provide web request and AES - * operation thread pool sizes. Uses the SecureRandom NativePRNGNonBlocking instance for random - * number generation. - * - * @param tspDomain Domain where the Tenant Security Proxy is running. - * @param apiKey Key to use for requests to the Tenant Security Proxy. - * @param requestThreadSize Number of threads to use for fixed-size web request thread pool - * @param aesThreadSize Number of threads to use for fixed-size AES operations threadpool - * @throws Exception If the provided domain is invalid. - */ - public TenantSecurityClient(String tspDomain, String apiKey, int requestThreadSize, - int aesThreadSize) throws Exception { - this(tspDomain, apiKey, requestThreadSize, aesThreadSize, - SecureRandom.getInstance("NativePRNGNonBlocking")); - } - - /** - * Constructor for TenantSecurityClient class that allows call to provide web request and AES - * operation thread pool sizes. Uses the SecureRandom NativePRNGNonBlocking instance for random - * number generation. - * - * @param tspDomain Domain where the Tenant Security Proxy is running. - * @param apiKey Key to use for requests to the Tenant Security Proxy. - * @param requestThreadSize Number of threads to use for fixed-size web request thread pool - * @param aesThreadSize Number of threads to use for fixed-size AES operations threadpool - * @param timeout Request to TSP read and connect timeout in ms. - * - * @throws Exception If the provided domain is invalid. - */ - public TenantSecurityClient(String tspDomain, String apiKey, int requestThreadSize, - int aesThreadSize, int timeout) throws Exception { - this(tspDomain, apiKey, requestThreadSize, aesThreadSize, - SecureRandom.getInstance("NativePRNGNonBlocking"), timeout); - } - - /** - * Constructor for TenantSecurityClient class that allows for modifying the random number - * generator used for encryption. Sets a default connect and read timeout of 20s. - * - * @param tspDomain Domain where the Tenant Security Proxy is running. - * @param apiKey Key to use for requests to the Tenant Security Proxy. - * @param requestThreadSize Number of threads to use for fixed-size web request thread pool - * @param aesThreadSize Number of threads to use for fixed-size AES operations threadpool - * @param randomGen Instance of SecureRandom to use for PRNG when performing encryption - * operations. - * @throws Exception If the provided domain is invalid or the provided SecureRandom instance is - * not set. - */ - public TenantSecurityClient(String tspDomain, String apiKey, int requestThreadSize, - int aesThreadSize, SecureRandom randomGen) throws Exception { - this(tspDomain, apiKey, requestThreadSize, aesThreadSize, randomGen, DEFAULT_TIMEOUT_MS); - } - - /** - * Constructor for TenantSecurityClient class that allows for modifying the random number - * generator used for encryption. - * - * @param tspDomain Domain where the Tenant Security Proxy is running. - * @param apiKey Key to use for requests to the Tenant Security Proxy. - * @param requestThreadSize Number of threads to use for fixed-size web request thread pool - * @param aesThreadSize Number of threads to use for fixed-size AES operations threadpool - * @param randomGen Instance of SecureRandom to use for PRNG when performing encryption - * operations. - * @param timeout Request to TSP read and connect timeout in ms. - * @throws Exception If the provided domain is invalid or the provided SecureRandom instance is - * not set. - */ - public TenantSecurityClient(String tspDomain, String apiKey, int requestThreadSize, - int aesThreadSize, SecureRandom randomGen, int timeout) throws Exception { - // Use the URL class to validate the form of the provided TSP domain URL - new URL(tspDomain); - if (apiKey == null || apiKey.isEmpty()) { + if (builder.apiKey == null || builder.apiKey.isEmpty()) { throw new IllegalArgumentException("No value provided for apiKey!"); } - if (randomGen == null) { + if (builder.randomGen == null) { throw new IllegalArgumentException("No value provided for random number generator!"); } - if (requestThreadSize < 1) { + if (builder.requestThreadSize < 1) { throw new IllegalArgumentException( "Value provided for request threadpool size must be greater than 0!"); } - if (aesThreadSize < 1) { + if (builder.aesThreadSize < 1) { throw new IllegalArgumentException( "Value provided for AES threadpool size must be greater than 0!"); } - if (timeout < 1) { + if (builder.timeout < 1) { throw new IllegalArgumentException("Value provided for timeout must be greater than 0!"); } - this.encryptionExecutor = Executors.newFixedThreadPool(aesThreadSize); - this.encryptionService = - new TenantSecurityRequest(tspDomain, apiKey, requestThreadSize, timeout); + this.encryptionExecutor = Executors.newFixedThreadPool(builder.aesThreadSize); + this.encryptionService = new TenantSecurityRequest(builder.tspDomain, builder.apiKey, + builder.requestThreadSize, builder.timeout); this.deterministicClient = new DeterministicTenantSecurityClient(this.encryptionExecutor, this.encryptionService); - // Update the crypto policy to allow us to use 256 bit AES keys Security.setProperty("crypto.policy", "unlimited"); - this.secureRandom = randomGen; + this.secureRandom = builder.randomGen; + } + + /** + * Ensures that the url is valid and if allowInsecureHttp is false that the tsp url must be https. + * Will throw if the URL isn't valid or if https is enforced and not provided. + * + * @param url The Url to check + * @param allowInsecureHttp If normal http should be allowed. + */ + private static void checkUrlForm(String url, boolean allowInsecureHttp) { + try { + URL parsed = new URL(url); + String protocol = parsed.getProtocol(); + if (!allowInsecureHttp && !"https".equalsIgnoreCase(protocol)) { + throw new IllegalArgumentException("Insecure HTTP URL not allowed: " + url); + } + } catch (MalformedURLException e) { + throw new IllegalArgumentException("Invalid URL: " + url, e); + } + } + + public static class Builder { + + /** + * Default size of web request thread pool. Defaults to 25. + */ + public static int DEFAULT_REQUEST_THREADPOOL_SIZE = 25; + + /** + * Default size of the threadpool used for AES encryptions/decryptions. Defaults to the number + * of cores on the machine being run on. + */ + public static int DEFAULT_AES_THREADPOOL_SIZE = Runtime.getRuntime().availableProcessors(); + + /** + * Default timeout in ms for the connection to the TSP. + */ + public static int DEFAULT_TIMEOUT_MS = 20000; + + private final String tspDomain; + private final String apiKey; + + private int requestThreadSize = DEFAULT_REQUEST_THREADPOOL_SIZE; + private int aesThreadSize = DEFAULT_AES_THREADPOOL_SIZE; + private int timeout = DEFAULT_TIMEOUT_MS; + private boolean allowInsecureHttp = false; + // If this is null when build is called we set it to the default. Don't set it here + // in case the default isn't available on their OS. + private SecureRandom randomGen = null; + + /** + * Builder for TenantSecurityClient class. + * + * @param tspDomain Domain where the Tenant Security Proxy is running. + * @param apiKey Key to use for requests to the Tenant Security Proxy. + * @param tspDomain + * @param apiKey + */ + public Builder(String tspDomain, String apiKey) { + this.tspDomain = tspDomain; + this.apiKey = apiKey; + } + + /** + * Sets the web request pool size. Defaults to DEFAULT_REQUEST_THREADPOOL_SIZE. + * + * @param size Number of threads to use for fixed-size web request thread pool. + * @return The builder + */ + public Builder requestThreadSize(int size) { + this.requestThreadSize = size; + return this; + } + + /** + * Sets the number of threads to use for fixed-size AES operations threadpool. Defaults to + * DEFAULT_AES_THREADPOOL_SIZE + * + * @param size The size of the aes thread pool. + * @return The builder + */ + public Builder aesThreadSize(int size) { + this.aesThreadSize = size; + return this; + } + + /** + * Sets the timeout in milliseconds for communicating with the TSP. + * + * @param timeout Timeout in milliseconds for the TSP requests. + * @return The builder + */ + public Builder timeoutMs(int timeout) { + this.timeout = timeout; + return this; + } + + /** + * Sets the random number generator. This should be set with care as the generator must be + * cryptographically secure. Defaults to "NativePRNGNonBlocking" + * + * @param random A new random number generator to use. + * @return The builder + */ + public Builder random(SecureRandom random) { + this.randomGen = random; + return this; + } + + /** + * Sets allowInsecureHttp. Defaults to false. + * + * @param allow If the TSP is allowed to be reachable via http. + * @return The builder + */ + public Builder allowInsecureHttp(boolean allow) { + this.allowInsecureHttp = allow; + return this; + } + + /** + * Construct the TenantSecurityClient fron the builder. + * + * @return The newly constructed TenantSecurityClient. + * @throws Exception If the tsp url isn't valid or if HTTPS is required and not provided. + */ + public TenantSecurityClient build() throws Exception { + // Check this here in case they don't have support for NativePRNGNonBlocking. + if (this.randomGen == null) { + this.randomGen = SecureRandom.getInstance("NativePRNGNonBlocking"); + } + return new TenantSecurityClient(this); + } } public void close() throws IOException { @@ -191,7 +227,8 @@ public DeterministicTenantSecurityClient getDeterministicClient() { * @return CompletableFuture that resolves in a instance of the TenantSecurityClient class. */ public static CompletableFuture create(String tspDomain, String apiKey) { - return CompletableFutures.tryCatchNonFatal(() -> new TenantSecurityClient(tspDomain, apiKey)); + return CompletableFutures + .tryCatchNonFatal(() -> new TenantSecurityClient.Builder(tspDomain, apiKey).build()); } /** diff --git a/src/main/java/com/ironcorelabs/tenantsecurity/kms/v1/TenantSecurityRequest.java b/src/main/java/com/ironcorelabs/tenantsecurity/kms/v1/TenantSecurityRequest.java index f417cc6..e30c5c3 100644 --- a/src/main/java/com/ironcorelabs/tenantsecurity/kms/v1/TenantSecurityRequest.java +++ b/src/main/java/com/ironcorelabs/tenantsecurity/kms/v1/TenantSecurityRequest.java @@ -20,7 +20,7 @@ import com.google.api.client.http.json.JsonHttpContent; import com.google.api.client.json.JsonFactory; import com.google.api.client.json.JsonObjectParser; -import com.google.api.client.json.jackson2.JacksonFactory; +import com.google.api.client.json.gson.GsonFactory; import com.google.api.client.util.Value; import com.ironcorelabs.tenantsecurity.kms.v1.exception.TenantSecurityException; import com.ironcorelabs.tenantsecurity.kms.v1.exception.TspServiceException; @@ -35,7 +35,11 @@ * works to parse out error codes on wrap/unwrap failures. */ final class TenantSecurityRequest implements Closeable { - private static final JsonFactory JSON_FACTORY = new JacksonFactory(); + private static final JsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance(); + + private static String stripTrailingSlash(String s) { + return (s == null) ? null : s.replaceAll("/+$", ""); + } // Fixed sized thread pool for web requests. Limit the amount of parallel web // requests that we let go out at any given time. We don't want to DoS our @@ -55,7 +59,7 @@ final class TenantSecurityRequest implements Closeable { private final int timeout; // TSC version that will be sent to the TSP. - static final String sdkVersion = "7.2.3"; + static final String sdkVersion = "8.0.1"; TenantSecurityRequest(String tspDomain, String apiKey, int requestThreadSize, int timeout) { HttpHeaders headers = new HttpHeaders(); @@ -67,8 +71,7 @@ final class TenantSecurityRequest implements Closeable { headers.put("x-icl-tsc-version", sdkVersion); this.httpHeaders = headers; - - String tspApiPrefix = tspDomain + "/api/1/"; + String tspApiPrefix = stripTrailingSlash(tspDomain) + "/api/1/"; this.wrapEndpoint = new GenericUrl(tspApiPrefix + "document/wrap"); this.batchWrapEndpoint = new GenericUrl(tspApiPrefix + "document/batch-wrap"); this.unwrapEndpoint = new GenericUrl(tspApiPrefix + "document/unwrap"); diff --git a/src/test/java/com/ironcorelabs/tenantsecurity/TestUtils.java b/src/test/java/com/ironcorelabs/tenantsecurity/TestUtils.java new file mode 100644 index 0000000..6c0a205 --- /dev/null +++ b/src/test/java/com/ironcorelabs/tenantsecurity/TestUtils.java @@ -0,0 +1,20 @@ +package com.ironcorelabs.tenantsecurity; + +import java.util.concurrent.CompletableFuture; +import com.ironcorelabs.tenantsecurity.kms.v1.TenantSecurityClient; +import com.ironcorelabs.tenantsecurity.utils.CompletableFutures; + +public class TestUtils { + public static CompletableFuture createTscWithAllowInsecure( + String tspAddress, String apiKey) { + return CompletableFutures.tryCatchNonFatal( + () -> new TenantSecurityClient.Builder(tspAddress, apiKey).allowInsecureHttp(true).build()); + } + + public static String ensureLeadingColon(String input) { + if (input == null || input.isEmpty()) { + return ":"; + } + return input.charAt(0) == ':' ? input : ":" + input; + } +} diff --git a/src/test/java/com/ironcorelabs/tenantsecurity/kms/v1/DevIntegrationTest.java b/src/test/java/com/ironcorelabs/tenantsecurity/kms/v1/DevIntegrationTest.java index 6f8afea..d68c6ca 100644 --- a/src/test/java/com/ironcorelabs/tenantsecurity/kms/v1/DevIntegrationTest.java +++ b/src/test/java/com/ironcorelabs/tenantsecurity/kms/v1/DevIntegrationTest.java @@ -11,10 +11,10 @@ import java.util.concurrent.CompletionException; import java.util.concurrent.ConcurrentMap; import java.util.stream.Collectors; +import com.ironcorelabs.tenantsecurity.TestUtils; import com.ironcorelabs.tenantsecurity.kms.v1.exception.TenantSecurityException; import com.ironcorelabs.tenantsecurity.logdriver.v1.EventMetadata; import com.ironcorelabs.tenantsecurity.logdriver.v1.UserEvent; - import org.testng.annotations.Test; @Test(groups = {"dev-integration"}) @@ -24,44 +24,12 @@ public class DevIntegrationTest { private String AZURE_TENANT_ID = "INTEGRATION-TEST-AZURE"; private String INTEGRATION_API_KEY = System.getenv("API_KEY"); - @Test(expectedExceptions = java.net.MalformedURLException.class) - public void constructorUrlTest() throws Exception { - new TenantSecurityClient("foobaz", "apiKey").close(); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void missingApiKeyTest() throws Exception { - new TenantSecurityClient("http://localhost", null).close(); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void emptyApiKeyTest() throws Exception { - new TenantSecurityClient("http://localhost", "").close(); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void invalidRequestThreadpoolSize() throws Exception { - new TenantSecurityClient("http://localhost", "apiKey", 0, 1).close(); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void invalidCryptoThreadpoolSize() throws Exception { - new TenantSecurityClient("http://localhost", "apiKey", 1, 0).close(); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void missingRandomGen() throws Exception { - new TenantSecurityClient("http://localhost", "apiKey", - TenantSecurityClient.DEFAULT_REQUEST_THREADPOOL_SIZE, - TenantSecurityClient.DEFAULT_AES_THREADPOOL_SIZE, null).close(); - } - private void assertEqualBytes(byte[] one, byte[] two) throws Exception { assertEquals(new String(one, "UTF-8"), new String(two, "UTF-8")); } private CompletableFuture getClient() { - return TenantSecurityClient.create(TestSettings.TSP_ADDRESS + TestSettings.TSP_PORT, + return TestUtils.createTscWithAllowInsecure(TestSettings.TSP_ADDRESS + TestSettings.TSP_PORT, this.INTEGRATION_API_KEY); } diff --git a/src/test/java/com/ironcorelabs/tenantsecurity/kms/v1/ErrorResponseTest.java b/src/test/java/com/ironcorelabs/tenantsecurity/kms/v1/ErrorResponseTest.java index a1e3cea..003e08d 100644 --- a/src/test/java/com/ironcorelabs/tenantsecurity/kms/v1/ErrorResponseTest.java +++ b/src/test/java/com/ironcorelabs/tenantsecurity/kms/v1/ErrorResponseTest.java @@ -2,12 +2,6 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.nio.ByteBuffer; -import java.security.SecureRandom; -import java.util.Arrays; -import java.util.stream.IntStream; import org.testng.annotations.Test; import com.ironcorelabs.tenantsecurity.kms.v1.exception.KmsException; import com.ironcorelabs.tenantsecurity.kms.v1.exception.SecurityEventException; diff --git a/src/test/java/com/ironcorelabs/tenantsecurity/kms/v1/KMSClientTest.java b/src/test/java/com/ironcorelabs/tenantsecurity/kms/v1/KMSClientTest.java index 0de490b..86d2bcc 100644 --- a/src/test/java/com/ironcorelabs/tenantsecurity/kms/v1/KMSClientTest.java +++ b/src/test/java/com/ironcorelabs/tenantsecurity/kms/v1/KMSClientTest.java @@ -5,35 +5,40 @@ @Test(groups = {"unit"}) public class KMSClientTest { - @Test(expectedExceptions = java.net.MalformedURLException.class) + @Test(expectedExceptions = IllegalArgumentException.class) public void constructorUrlTest() throws Exception { - new TenantSecurityClient("foobaz", "apiKey").close(); + new TenantSecurityClient.Builder("foobaz", "apiKey").build().close(); } @Test(expectedExceptions = IllegalArgumentException.class) public void missingApiKeyTest() throws Exception { - new TenantSecurityClient("http://localhost", null).close(); + new TenantSecurityClient.Builder("https://localhost", null).build().close(); } @Test(expectedExceptions = IllegalArgumentException.class) public void emptyApiKeyTest() throws Exception { - new TenantSecurityClient("http://localhost", "").close(); + new TenantSecurityClient.Builder("https://localhost", "").build().close(); } @Test(expectedExceptions = IllegalArgumentException.class) - public void invalidRequestThreadpoolSize() throws Exception { - new TenantSecurityClient("http://localhost", "apiKey", 0, 1).close(); + public void httpsOnlyIsOnAndTryToUseHttpTest() throws Exception { + new TenantSecurityClient.Builder("http://localhost", "apiKey").build().close(); + } + + // Just a sanity check to ensure the default allows https + public void httpsOnlyIsOnAndTryToUseHttpsTest() throws Exception { + new TenantSecurityClient.Builder("https://localhost", "apiKey").build().close(); } @Test(expectedExceptions = IllegalArgumentException.class) - public void invalidCryptoThreadpoolSize() throws Exception { - new TenantSecurityClient("http://localhost", "apiKey", 1, 0).close(); + public void invalidRequestThreadpoolSize() throws Exception { + new TenantSecurityClient.Builder("https://localhost", "apiKey").requestThreadSize(0).build() + .close(); } @Test(expectedExceptions = IllegalArgumentException.class) - public void missingRandomGen() throws Exception { - new TenantSecurityClient("http://localhost", "apiKey", - TenantSecurityClient.DEFAULT_REQUEST_THREADPOOL_SIZE, - TenantSecurityClient.DEFAULT_AES_THREADPOOL_SIZE, null).close(); + public void invalidCryptoThreadpoolSize() throws Exception { + new TenantSecurityClient.Builder("https://localhost", "apiKey").aesThreadSize(0).build() + .close(); } } diff --git a/src/test/java/com/ironcorelabs/tenantsecurity/kms/v1/KMSRequestTest.java b/src/test/java/com/ironcorelabs/tenantsecurity/kms/v1/KMSRequestTest.java index 7aa805b..61a17fc 100644 --- a/src/test/java/com/ironcorelabs/tenantsecurity/kms/v1/KMSRequestTest.java +++ b/src/test/java/com/ironcorelabs/tenantsecurity/kms/v1/KMSRequestTest.java @@ -9,6 +9,7 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import com.ironcorelabs.tenantsecurity.TestUtils; import com.ironcorelabs.tenantsecurity.kms.v1.exception.TenantSecurityException; import org.testng.annotations.Test; @@ -32,7 +33,7 @@ private Map getDocument() { public void errorCodeWhenServiceNotReachable() throws Exception { CompletableFuture encrypt = - TenantSecurityClient.create("http://thisdomaindoesnotexist.eta", "apiKey") + TenantSecurityClient.create("https://thisdomaindoesnotexist.eta", "apiKey") .thenCompose(client -> client.encrypt(getDocument(), getMetadata())); try { @@ -47,9 +48,9 @@ public void errorCodeWhenServiceNotReachable() throws Exception { } public void errorCodeWhenApiKeyIsWrong() throws Exception { - CompletableFuture encrypt = - TenantSecurityClient.create(TestSettings.TSP_ADDRESS + TestSettings.TSP_PORT, "wrongKey") - .thenCompose(client -> client.encrypt(getDocument(), getMetadata())); + CompletableFuture encrypt = TestUtils + .createTscWithAllowInsecure(TestSettings.TSP_ADDRESS + TestSettings.TSP_PORT, "wrongKey") + .thenCompose(client -> client.encrypt(getDocument(), getMetadata())); try { encrypt.get(); @@ -66,8 +67,8 @@ public void errorCodeWhenEdekFormatIsWrong() throws Exception { documentMap.put("doc", new byte[] {3, 73, 82, 79, 78}); EncryptedDocument eDoc = new EncryptedDocument(documentMap, "d2hhdCBhIHdhc3RlIG9mIHRpbWUK"); - CompletableFuture decrypt = TenantSecurityClient - .create(TestSettings.TSP_ADDRESS + TestSettings.TSP_PORT, + CompletableFuture decrypt = TestUtils + .createTscWithAllowInsecure(TestSettings.TSP_ADDRESS + TestSettings.TSP_PORT, NotPrimaryAndDisabledConfigs.INTEGRATION_API_KEY) .thenCompose(client -> client.decrypt(eDoc, getMetadata())); diff --git a/src/test/java/com/ironcorelabs/tenantsecurity/kms/v1/LocalBatch.java b/src/test/java/com/ironcorelabs/tenantsecurity/kms/v1/LocalBatch.java index f97dd3c..c2185a5 100644 --- a/src/test/java/com/ironcorelabs/tenantsecurity/kms/v1/LocalBatch.java +++ b/src/test/java/com/ironcorelabs/tenantsecurity/kms/v1/LocalBatch.java @@ -59,7 +59,8 @@ public void batchRoundtrip() throws Exception { DocumentMetadata context = new DocumentMetadata(this.TENANT_ID, "integrationTest", "sample"); TenantSecurityClient client = - new TenantSecurityClient(TestSettings.TSP_ADDRESS + TestSettings.TSP_PORT, this.API_KEY); + new TenantSecurityClient.Builder(TestSettings.TSP_ADDRESS + TestSettings.TSP_PORT, + this.API_KEY).build(); int batchSize = 25; int batchRepetitions = 50; diff --git a/src/test/java/com/ironcorelabs/tenantsecurity/kms/v1/LocalRoundTrip.java b/src/test/java/com/ironcorelabs/tenantsecurity/kms/v1/LocalRoundTrip.java index 463dce9..2930ee9 100644 --- a/src/test/java/com/ironcorelabs/tenantsecurity/kms/v1/LocalRoundTrip.java +++ b/src/test/java/com/ironcorelabs/tenantsecurity/kms/v1/LocalRoundTrip.java @@ -8,9 +8,11 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import java.util.concurrent.ExecutionException; +import com.ironcorelabs.tenantsecurity.TestUtils; import com.ironcorelabs.tenantsecurity.kms.v1.exception.TenantSecurityException; import com.ironcorelabs.tenantsecurity.logdriver.v1.EventMetadata; import com.ironcorelabs.tenantsecurity.logdriver.v1.UserEvent; +import com.ironcorelabs.tenantsecurity.utils.CompletableFutures; import org.testng.annotations.Test; @Test(groups = {"local-integration"}) @@ -39,20 +41,18 @@ public void roundtripTest() throws Exception { Map envVars = System.getenv(); String tsp_address = envVars.getOrDefault("TSP_ADDRESS", TestSettings.TSP_ADDRESS); - String tsp_port = envVars.getOrDefault("TSP_PORT", TestSettings.TSP_PORT); + String tsp_port = + TestUtils.ensureLeadingColon(envVars.getOrDefault("TSP_PORT", TestSettings.TSP_PORT)); String api_key = envVars.getOrDefault("API_KEY", API_KEY); String tenant_id = envVars.getOrDefault("TENANT_ID", TENANT_ID); - if (tsp_port.charAt(0) != ':') { - tsp_port = ":" + tsp_port; - } DocumentMetadata context = new DocumentMetadata(tenant_id, "integrationTest", "sample", customFields, "customRayID"); Map documentMap = getRoundtripDataToEncrypt(); - CompletableFuture roundtrip = - TenantSecurityClient.create(tsp_address + tsp_port, api_key).thenCompose(client -> { + CompletableFuture roundtrip = TestUtils + .createTscWithAllowInsecure(tsp_address + tsp_port, api_key).thenCompose(client -> { try { return client.encrypt(documentMap, context).thenCompose(encryptedResults -> { @@ -94,17 +94,13 @@ public void logSecurityEventBadTenant() throws Exception { String api_key = envVars.getOrDefault("API_KEY", API_KEY); String tenant_id = "bad-tenant-id"; - if (tsp_port.charAt(0) != ':') { - tsp_port = ":" + tsp_port; - } - EventMetadata metadata = new EventMetadata(tenant_id, "integrationTest", "sample", "app-request-id"); // even though this tenant is bad, the response here will be success as the security // event was enqueued for further processing. - CompletableFuture logEvent = - TenantSecurityClient.create(tsp_address + tsp_port, api_key).thenCompose(client -> { + CompletableFuture logEvent = TestUtils + .createTscWithAllowInsecure(tsp_address + tsp_port, api_key).thenCompose(client -> { return client.logSecurityEvent(UserEvent.ADD, metadata); }); diff --git a/src/test/java/com/ironcorelabs/tenantsecurity/kms/v1/NotPrimaryAndDisabledConfigs.java b/src/test/java/com/ironcorelabs/tenantsecurity/kms/v1/NotPrimaryAndDisabledConfigs.java index 249413c..7ac8037 100644 --- a/src/test/java/com/ironcorelabs/tenantsecurity/kms/v1/NotPrimaryAndDisabledConfigs.java +++ b/src/test/java/com/ironcorelabs/tenantsecurity/kms/v1/NotPrimaryAndDisabledConfigs.java @@ -7,8 +7,9 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; - +import com.ironcorelabs.tenantsecurity.TestUtils; import com.ironcorelabs.tenantsecurity.kms.v1.exception.TenantSecurityException; +import com.ironcorelabs.tenantsecurity.utils.CompletableFutures; import org.testng.annotations.Test; @Test(groups = {"dev-integration"}) @@ -61,7 +62,7 @@ private void assertEqualBytes(byte[] one, byte[] two) throws Exception { } private CompletableFuture getClient() { - return TenantSecurityClient.create(TestSettings.TSP_ADDRESS + TestSettings.TSP_PORT, + return TestUtils.createTscWithAllowInsecure(TestSettings.TSP_ADDRESS + TestSettings.TSP_PORT, NotPrimaryAndDisabledConfigs.INTEGRATION_API_KEY); }