From 012d58c92beef833b0e193cb328d7db6d572c208 Mon Sep 17 00:00:00 2001 From: skyflow-vivek Date: Thu, 13 Feb 2025 14:30:59 +0530 Subject: [PATCH 1/9] SK-1875 Add separate redaction types for tokens in Detokenize --- src/main/java/com/skyflow/VaultClient.java | 8 ++- .../utils/validations/Validations.java | 11 ++-- .../skyflow/vault/tokens/DetokenizeData.java | 26 +++++++++ .../vault/tokens/DetokenizeRequest.java | 32 +++++------ .../java/com/skyflow/VaultClientTests.java | 15 +++-- .../skyflow/vault/tokens/DetokenizeTests.java | 57 +++++++++++-------- 6 files changed, 95 insertions(+), 54 deletions(-) create mode 100644 src/main/java/com/skyflow/vault/tokens/DetokenizeData.java diff --git a/src/main/java/com/skyflow/VaultClient.java b/src/main/java/com/skyflow/VaultClient.java index f3e29fb2..eb1cc3fa 100644 --- a/src/main/java/com/skyflow/VaultClient.java +++ b/src/main/java/com/skyflow/VaultClient.java @@ -20,6 +20,7 @@ import com.skyflow.vault.data.InsertRequest; import com.skyflow.vault.data.UpdateRequest; import com.skyflow.vault.tokens.ColumnValue; +import com.skyflow.vault.tokens.DetokenizeData; import com.skyflow.vault.tokens.DetokenizeRequest; import com.skyflow.vault.tokens.TokenizeRequest; import io.github.cdimascio.dotenv.Dotenv; @@ -85,10 +86,11 @@ protected void updateVaultConfig() throws SkyflowException { protected V1DetokenizePayload getDetokenizePayload(DetokenizeRequest request) { V1DetokenizePayload payload = new V1DetokenizePayload(); payload.setContinueOnError(request.getContinueOnError()); - for (String token : request.getTokens()) { + payload.setDownloadURL(request.getDownloadURL()); + for (DetokenizeData detokenizeDataRecord : request.getDetokenizeData()) { V1DetokenizeRecordRequest recordRequest = new V1DetokenizeRecordRequest(); - recordRequest.setToken(token); - recordRequest.setRedaction(request.getRedactionType().getRedaction()); + recordRequest.setToken(detokenizeDataRecord.getToken()); + recordRequest.setRedaction(detokenizeDataRecord.getRedactionType().getRedaction()); payload.addDetokenizationParametersItem(recordRequest); } return payload; diff --git a/src/main/java/com/skyflow/utils/validations/Validations.java b/src/main/java/com/skyflow/utils/validations/Validations.java index 2876c15d..8b7b6fef 100644 --- a/src/main/java/com/skyflow/utils/validations/Validations.java +++ b/src/main/java/com/skyflow/utils/validations/Validations.java @@ -18,6 +18,7 @@ import com.skyflow.vault.connection.InvokeConnectionRequest; import com.skyflow.vault.data.*; import com.skyflow.vault.tokens.ColumnValue; +import com.skyflow.vault.tokens.DetokenizeData; import com.skyflow.vault.tokens.DetokenizeRequest; import com.skyflow.vault.tokens.TokenizeRequest; @@ -212,20 +213,20 @@ public static void validateCredentials(Credentials credentials) throws SkyflowEx } public static void validateDetokenizeRequest(DetokenizeRequest detokenizeRequest) throws SkyflowException { - ArrayList tokens = detokenizeRequest.getTokens(); - if (tokens == null) { + ArrayList detokenizeData = detokenizeRequest.getDetokenizeData(); + if (detokenizeData == null) { LogUtil.printErrorLog(Utils.parameterizedString( ErrorLogs.TOKENS_REQUIRED.getLog(), InterfaceName.DETOKENIZE.getName() )); throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidDataTokens.getMessage()); - } else if (tokens.isEmpty()) { + } else if (detokenizeData.isEmpty()) { LogUtil.printErrorLog(Utils.parameterizedString( ErrorLogs.EMPTY_TOKENS.getLog(), InterfaceName.DETOKENIZE.getName() )); throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyDataTokens.getMessage()); } else { - for (int index = 0; index < tokens.size(); index++) { - String token = tokens.get(index); + for (int index = 0; index < detokenizeData.size(); index++) { + String token = detokenizeData.get(index).getToken(); if (token == null || token.trim().isEmpty()) { LogUtil.printErrorLog(Utils.parameterizedString( ErrorLogs.EMPTY_OR_NULL_TOKEN_IN_TOKENS.getLog(), diff --git a/src/main/java/com/skyflow/vault/tokens/DetokenizeData.java b/src/main/java/com/skyflow/vault/tokens/DetokenizeData.java new file mode 100644 index 00000000..33bba2b9 --- /dev/null +++ b/src/main/java/com/skyflow/vault/tokens/DetokenizeData.java @@ -0,0 +1,26 @@ +package com.skyflow.vault.tokens; + +import com.skyflow.enums.RedactionType; + +public class DetokenizeData { + private final String token; + private final RedactionType redactionType; + + public DetokenizeData(String token) { + this.token = token; + this.redactionType = RedactionType.PLAIN_TEXT; + } + + public DetokenizeData(String token, RedactionType redactionType) { + this.token = token; + this.redactionType = redactionType == null ? RedactionType.PLAIN_TEXT : redactionType; + } + + public String getToken() { + return this.token; + } + + public RedactionType getRedactionType() { + return this.redactionType; + } +} diff --git a/src/main/java/com/skyflow/vault/tokens/DetokenizeRequest.java b/src/main/java/com/skyflow/vault/tokens/DetokenizeRequest.java index d5b8f072..186a18d2 100644 --- a/src/main/java/com/skyflow/vault/tokens/DetokenizeRequest.java +++ b/src/main/java/com/skyflow/vault/tokens/DetokenizeRequest.java @@ -1,7 +1,5 @@ package com.skyflow.vault.tokens; -import com.skyflow.enums.RedactionType; - import java.util.ArrayList; public class DetokenizeRequest { @@ -15,40 +13,40 @@ public static DetokenizeRequestBuilder builder() { return new DetokenizeRequestBuilder(); } - public ArrayList getTokens() { - return this.builder.tokens; - } - - public RedactionType getRedactionType() { - return this.builder.redactionType; + public ArrayList getDetokenizeData() { + return this.builder.detokenizeData; } public Boolean getContinueOnError() { return this.builder.continueOnError; } + public Boolean getDownloadURL() { + return this.builder.downloadURL; + } + public static final class DetokenizeRequestBuilder { - private ArrayList tokens; - private RedactionType redactionType; + private ArrayList detokenizeData; private Boolean continueOnError; + private Boolean downloadURL; private DetokenizeRequestBuilder() { - this.redactionType = RedactionType.PLAIN_TEXT; this.continueOnError = false; + this.downloadURL = false; } - public DetokenizeRequestBuilder tokens(ArrayList tokens) { - this.tokens = tokens; + public DetokenizeRequestBuilder detokenizeData(ArrayList detokenizeData) { + this.detokenizeData = detokenizeData; return this; } - public DetokenizeRequestBuilder redactionType(RedactionType redactionType) { - this.redactionType = redactionType == null ? RedactionType.PLAIN_TEXT : redactionType; + public DetokenizeRequestBuilder continueOnError(Boolean continueOnError) { + this.continueOnError = continueOnError != null && continueOnError; return this; } - public DetokenizeRequestBuilder continueOnError(Boolean continueOnError) { - this.continueOnError = continueOnError != null && continueOnError; + public DetokenizeRequestBuilder downloadURL(Boolean downloadURL) { + this.downloadURL = downloadURL; return this; } diff --git a/src/test/java/com/skyflow/VaultClientTests.java b/src/test/java/com/skyflow/VaultClientTests.java index 8a02caaf..0cd99614 100644 --- a/src/test/java/com/skyflow/VaultClientTests.java +++ b/src/test/java/com/skyflow/VaultClientTests.java @@ -9,6 +9,7 @@ import com.skyflow.vault.data.InsertRequest; import com.skyflow.vault.data.UpdateRequest; import com.skyflow.vault.tokens.ColumnValue; +import com.skyflow.vault.tokens.DetokenizeData; import com.skyflow.vault.tokens.DetokenizeRequest; import com.skyflow.vault.tokens.TokenizeRequest; import io.github.cdimascio.dotenv.Dotenv; @@ -31,7 +32,7 @@ public class VaultClientTests { private static String value = null; private static String columnGroup = null; private static String apiKey = null; - private static ArrayList tokens = null; + private static ArrayList detokenizeData = null; private static ArrayList> insertValues = null; private static ArrayList> insertTokens = null; private static HashMap valueMap = null; @@ -43,7 +44,7 @@ public static void setup() { vaultID = "vault123"; clusterID = "cluster123"; token = "test_token"; - tokens = new ArrayList<>(); + detokenizeData = new ArrayList<>(); table = "test_table"; value = "test_value"; columnGroup = "test_column_group"; @@ -115,11 +116,15 @@ public void testVaultClientGetVaultConfig() { @Test public void testGetDetokenizePayload() { try { - tokens.add(token); - tokens.add(token); - DetokenizeRequest detokenizeRequest = DetokenizeRequest.builder().tokens(tokens).build(); + DetokenizeData detokenizeDataRecord1 = new DetokenizeData(token); + DetokenizeData detokenizeDataRecord2 = new DetokenizeData(token); + detokenizeData.add(detokenizeDataRecord1); + detokenizeData.add(detokenizeDataRecord2); + DetokenizeRequest detokenizeRequest = DetokenizeRequest.builder() + .detokenizeData(detokenizeData).downloadURL(true).build(); V1DetokenizePayload payload = vaultClient.getDetokenizePayload(detokenizeRequest); Assert.assertFalse(payload.getContinueOnError()); + Assert.assertTrue(payload.getDownloadURL()); Assert.assertEquals(2, payload.getDetokenizationParameters().size()); } catch (Exception e) { Assert.fail(INVALID_EXCEPTION_THROWN); diff --git a/src/test/java/com/skyflow/vault/tokens/DetokenizeTests.java b/src/test/java/com/skyflow/vault/tokens/DetokenizeTests.java index 3577f7db..722a6c59 100644 --- a/src/test/java/com/skyflow/vault/tokens/DetokenizeTests.java +++ b/src/test/java/com/skyflow/vault/tokens/DetokenizeTests.java @@ -19,30 +19,33 @@ public class DetokenizeTests { private static final String INVALID_EXCEPTION_THROWN = "Should not have thrown any exception"; private static final String EXCEPTION_NOT_THROWN = "Should have thrown an exception"; - private static String token = null; - private static ArrayList tokens = null; + private static ArrayList detokenizeData = null; + private static DetokenizeData maskedRedactionRecord = null; + private static DetokenizeData plainRedactionRecord = null; @BeforeClass public static void setup() throws SkyflowException, NoSuchMethodException { - tokens = new ArrayList<>(); - token = "test_token_1"; + detokenizeData = new ArrayList<>(); + maskedRedactionRecord = new DetokenizeData("test_token_1", RedactionType.MASKED); + plainRedactionRecord = new DetokenizeData("test_token_2"); } @Before public void setupTest() { - tokens.clear(); + detokenizeData.clear(); } @Test public void testValidInputInDetokenizeRequestValidations() { try { - tokens.add(token); - DetokenizeRequest request = DetokenizeRequest.builder(). - tokens(tokens).redactionType(RedactionType.MASKED).continueOnError(false).build(); + detokenizeData.add(maskedRedactionRecord); + DetokenizeRequest request = DetokenizeRequest.builder() + .detokenizeData(detokenizeData).continueOnError(false).downloadURL(true).build(); Validations.validateDetokenizeRequest(request); - Assert.assertEquals(1, tokens.size()); - Assert.assertEquals(RedactionType.MASKED.toString(), request.getRedactionType().toString()); + Assert.assertEquals(1, request.getDetokenizeData().size()); + Assert.assertEquals(RedactionType.MASKED.toString(), request.getDetokenizeData().get(0).getRedactionType().toString()); Assert.assertFalse(request.getContinueOnError()); + Assert.assertTrue(request.getDownloadURL()); } catch (SkyflowException e) { Assert.fail(INVALID_EXCEPTION_THROWN); } @@ -60,14 +63,14 @@ public void testNoTokensInDetokenizeRequestValidations() { Utils.parameterizedString(ErrorMessage.InvalidDataTokens.getMessage(), Constants.SDK_PREFIX), e.getMessage() ); - Assert.assertEquals(RedactionType.PLAIN_TEXT, request.getRedactionType()); Assert.assertFalse(request.getContinueOnError()); + Assert.assertFalse(request.getDownloadURL()); } } @Test public void testEmptyTokensInDetokenizeRequestValidations() { - DetokenizeRequest request = DetokenizeRequest.builder().tokens(tokens).build(); + DetokenizeRequest request = DetokenizeRequest.builder().detokenizeData(detokenizeData).build(); try { Validations.validateDetokenizeRequest(request); Assert.fail(EXCEPTION_NOT_THROWN); @@ -77,16 +80,18 @@ public void testEmptyTokensInDetokenizeRequestValidations() { Utils.parameterizedString(ErrorMessage.EmptyDataTokens.getMessage(), Constants.SDK_PREFIX), e.getMessage() ); - Assert.assertEquals(RedactionType.PLAIN_TEXT, request.getRedactionType()); Assert.assertFalse(request.getContinueOnError()); + Assert.assertFalse(request.getDownloadURL()); } } @Test public void testEmptyTokenInTokensInDetokenizeRequestValidations() { - tokens.add(token); - tokens.add(""); - DetokenizeRequest request = DetokenizeRequest.builder().tokens(tokens).build(); + DetokenizeData detokenizeDataRecord = new DetokenizeData(""); + detokenizeData.add(maskedRedactionRecord); + detokenizeData.add(detokenizeDataRecord); + + DetokenizeRequest request = DetokenizeRequest.builder().detokenizeData(detokenizeData).build(); try { Validations.validateDetokenizeRequest(request); Assert.fail(EXCEPTION_NOT_THROWN); @@ -96,16 +101,18 @@ public void testEmptyTokenInTokensInDetokenizeRequestValidations() { Utils.parameterizedString(ErrorMessage.EmptyTokenInDataTokens.getMessage(), Constants.SDK_PREFIX), e.getMessage() ); - Assert.assertEquals(RedactionType.PLAIN_TEXT, request.getRedactionType()); Assert.assertFalse(request.getContinueOnError()); + Assert.assertFalse(request.getDownloadURL()); } } @Test public void testNullTokenInTokensInDetokenizeRequestValidations() { - tokens.add(token); - tokens.add(null); - DetokenizeRequest request = DetokenizeRequest.builder().tokens(tokens).build(); + DetokenizeData detokenizeDataRecord = new DetokenizeData(null); + detokenizeData.add(maskedRedactionRecord); + detokenizeData.add(detokenizeDataRecord); + + DetokenizeRequest request = DetokenizeRequest.builder().detokenizeData(detokenizeData).build(); try { Validations.validateDetokenizeRequest(request); Assert.fail(EXCEPTION_NOT_THROWN); @@ -115,20 +122,22 @@ public void testNullTokenInTokensInDetokenizeRequestValidations() { Utils.parameterizedString(ErrorMessage.EmptyTokenInDataTokens.getMessage(), Constants.SDK_PREFIX), e.getMessage() ); - Assert.assertEquals(RedactionType.PLAIN_TEXT, request.getRedactionType()); Assert.assertFalse(request.getContinueOnError()); + Assert.assertFalse(request.getDownloadURL()); } } @Test public void testRedactionAndContinueOnErrorInDetokenizeRequestValidations() { - tokens.add(token); + detokenizeData.add(plainRedactionRecord); + DetokenizeRequest request = DetokenizeRequest.builder(). - tokens(tokens).redactionType(null).continueOnError(null).build(); + detokenizeData(detokenizeData).continueOnError(null).build(); try { Validations.validateDetokenizeRequest(request); - Assert.assertEquals(RedactionType.PLAIN_TEXT, request.getRedactionType()); + Assert.assertEquals(RedactionType.PLAIN_TEXT, request.getDetokenizeData().get(0).getRedactionType()); Assert.assertFalse(request.getContinueOnError()); + Assert.assertFalse(request.getDownloadURL()); } catch (SkyflowException e) { Assert.fail(INVALID_EXCEPTION_THROWN); } From fe43c66cf784521092079d00ed3fe803ac61c729 Mon Sep 17 00:00:00 2001 From: skyflow-vivek Date: Thu, 13 Feb 2025 16:58:42 +0530 Subject: [PATCH 2/9] SK-1875 Add separate redaction types for tokens in Detokenize - Update error messages and logs according to changes - Update detokenize sample to work with new changes --- .../com/example/vault/DetokenizeExample.java | 27 +++++++++++-------- .../java/com/skyflow/errors/ErrorMessage.java | 6 ++--- src/main/java/com/skyflow/logs/ErrorLogs.java | 5 ++-- .../utils/validations/Validations.java | 12 ++++----- .../controller/VaultControllerTests.java | 2 +- .../skyflow/vault/tokens/DetokenizeTests.java | 12 ++++----- 6 files changed, 35 insertions(+), 29 deletions(-) diff --git a/samples/src/main/java/com/example/vault/DetokenizeExample.java b/samples/src/main/java/com/example/vault/DetokenizeExample.java index f25d2be0..78f102a3 100644 --- a/samples/src/main/java/com/example/vault/DetokenizeExample.java +++ b/samples/src/main/java/com/example/vault/DetokenizeExample.java @@ -7,6 +7,7 @@ import com.skyflow.enums.LogLevel; import com.skyflow.enums.RedactionType; import com.skyflow.errors.SkyflowException; +import com.skyflow.vault.tokens.DetokenizeData; import com.skyflow.vault.tokens.DetokenizeRequest; import com.skyflow.vault.tokens.DetokenizeResponse; @@ -52,13 +53,15 @@ public static void main(String[] args) throws SkyflowException { // Example 1: Detokenize tokens from the first vault try { - ArrayList tokens1 = new ArrayList<>(); - tokens1.add(""); // Replace with the first token to detokenize - tokens1.add(""); // Replace with the second token to detokenize + ArrayList detokenizeData1 = new ArrayList<>(); + DetokenizeData detokenizeDataRecord1 = new DetokenizeData("", RedactionType.MASKED); // Replace with a token to detokenize with MASKED redaction + DetokenizeData detokenizeDataRecord2 = new DetokenizeData(""); // Replace with another token to detokenize with PLAIN_TEXT redaction + detokenizeData1.add(detokenizeDataRecord1); + detokenizeData1.add(detokenizeDataRecord2); DetokenizeRequest detokenizeRequest1 = DetokenizeRequest.builder() - .tokens(tokens1) // Specify the tokens to detokenize - .continueOnError(true) // Continue processing even if an error occurs for some tokens + .detokenizeData(detokenizeData1) // Specify the tokens to detokenize with specified redaction types + .continueOnError(true) // Continue processing even if an error occurs for some tokens .build(); DetokenizeResponse detokenizeResponse1 = skyflowClient.vault().detokenize(detokenizeRequest1); // Perform detokenization @@ -70,14 +73,16 @@ public static void main(String[] args) throws SkyflowException { // Example 2: Detokenize tokens from the second vault try { - ArrayList tokens2 = new ArrayList<>(); - tokens2.add(""); // Replace with the first token to detokenize - tokens2.add(""); // Replace with the second token to detokenize + ArrayList detokenizeData2 = new ArrayList<>(); + DetokenizeData detokenizeDataRecord3 = new DetokenizeData("", RedactionType.DEFAULT); // Replace with a token to detokenize + DetokenizeData detokenizeDataRecord4 = new DetokenizeData(""); // Replace with another token to detokenize + detokenizeData2.add(detokenizeDataRecord3); + detokenizeData2.add(detokenizeDataRecord4); DetokenizeRequest detokenizeRequest2 = DetokenizeRequest.builder() - .tokens(tokens2) // Specify the tokens to detokenize - .continueOnError(false) // Stop processing on the first error - .redactionType(RedactionType.DEFAULT) // Use the default redaction type for detokenization + .detokenizeData(detokenizeData2) // Specify the tokens to detokenize with specified redaction types + .continueOnError(false) // Stop processing on the first error + .downloadURL(true) // Specify whether to return URLs for file data type .build(); DetokenizeResponse detokenizeResponse2 = skyflowClient.vault("").detokenize(detokenizeRequest2); // Perform detokenization diff --git a/src/main/java/com/skyflow/errors/ErrorMessage.java b/src/main/java/com/skyflow/errors/ErrorMessage.java index d6af06aa..da992da2 100644 --- a/src/main/java/com/skyflow/errors/ErrorMessage.java +++ b/src/main/java/com/skyflow/errors/ErrorMessage.java @@ -73,9 +73,9 @@ public enum ErrorMessage { BatchInsertFailure("%s0 Insert operation failed."), // detokenize - InvalidDataTokens("%s0 Validation error. Invalid data tokens. Specify valid data tokens."), - EmptyDataTokens("%s0 Validation error. Invalid data tokens. Specify at least one data token."), - EmptyTokenInDataTokens("%s0 Validation error. Invalid data tokens. Specify a valid data token."), + InvalidDetokenizeData("%s0 Validation error. Invalid detokenize data. Specify valid detokenize data."), + EmptyDetokenizeData("%s0 Validation error. Invalid data tokens. Specify at least one data token."), + EmptyTokenInDetokenizeData("%s0 Validation error. Invalid data tokens. Specify a valid data token."), // get interface IdsKeyError("%s0 Validation error. 'ids' key is missing from the payload. Specify an 'ids' key."), diff --git a/src/main/java/com/skyflow/logs/ErrorLogs.java b/src/main/java/com/skyflow/logs/ErrorLogs.java index 64e40c82..ad588aa0 100644 --- a/src/main/java/com/skyflow/logs/ErrorLogs.java +++ b/src/main/java/com/skyflow/logs/ErrorLogs.java @@ -61,8 +61,9 @@ public enum ErrorLogs { INSUFFICIENT_TOKENS_PASSED_FOR_TOKEN_MODE_ENABLE_STRICT("Invalid %s1 request. For tokenMode as ENABLE_STRICT, tokens should be passed for all fields."), MISMATCH_OF_FIELDS_AND_TOKENS("Invalid %s1 request. Keys for values and tokens are not matching."), INSERT_RECORDS_REJECTED("Insert request resulted in failure."), - TOKENS_REQUIRED("Invalid %s1 request. Tokens are required."), - EMPTY_OR_NULL_TOKEN_IN_TOKENS("Invalid %s1 request. Token can not be null or empty in tokens at index %s2."), + DETOKENIZE_DATA_REQUIRED("Invalid %s1 request. Detokenize data is required."), + EMPTY_DETOKENIZE_DATA("Invalid %s1 request. Detokenize data can not be empty."), + EMPTY_OR_NULL_TOKEN_IN_DETOKENIZE_DATA("Invalid %s1 request. Token can not be null or empty in detokenize data at index %s2."), REDACTION_IS_REQUIRED("Invalid %s1 request. Redaction is required."), DETOKENIZE_REQUEST_REJECTED("Detokenize request resulted in failure."), IDS_IS_REQUIRED("Invalid %s1 request. Ids are required."), diff --git a/src/main/java/com/skyflow/utils/validations/Validations.java b/src/main/java/com/skyflow/utils/validations/Validations.java index 8b7b6fef..5e192349 100644 --- a/src/main/java/com/skyflow/utils/validations/Validations.java +++ b/src/main/java/com/skyflow/utils/validations/Validations.java @@ -216,23 +216,23 @@ public static void validateDetokenizeRequest(DetokenizeRequest detokenizeRequest ArrayList detokenizeData = detokenizeRequest.getDetokenizeData(); if (detokenizeData == null) { LogUtil.printErrorLog(Utils.parameterizedString( - ErrorLogs.TOKENS_REQUIRED.getLog(), InterfaceName.DETOKENIZE.getName() + ErrorLogs.DETOKENIZE_DATA_REQUIRED.getLog(), InterfaceName.DETOKENIZE.getName() )); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidDataTokens.getMessage()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidDetokenizeData.getMessage()); } else if (detokenizeData.isEmpty()) { LogUtil.printErrorLog(Utils.parameterizedString( - ErrorLogs.EMPTY_TOKENS.getLog(), InterfaceName.DETOKENIZE.getName() + ErrorLogs.EMPTY_DETOKENIZE_DATA.getLog(), InterfaceName.DETOKENIZE.getName() )); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyDataTokens.getMessage()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyDetokenizeData.getMessage()); } else { for (int index = 0; index < detokenizeData.size(); index++) { String token = detokenizeData.get(index).getToken(); if (token == null || token.trim().isEmpty()) { LogUtil.printErrorLog(Utils.parameterizedString( - ErrorLogs.EMPTY_OR_NULL_TOKEN_IN_TOKENS.getLog(), + ErrorLogs.EMPTY_OR_NULL_TOKEN_IN_DETOKENIZE_DATA.getLog(), InterfaceName.DETOKENIZE.getName(), Integer.toString(index) )); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyTokenInDataTokens.getMessage()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyTokenInDetokenizeData.getMessage()); } } } diff --git a/src/test/java/com/skyflow/vault/controller/VaultControllerTests.java b/src/test/java/com/skyflow/vault/controller/VaultControllerTests.java index 66621003..6084e9c3 100644 --- a/src/test/java/com/skyflow/vault/controller/VaultControllerTests.java +++ b/src/test/java/com/skyflow/vault/controller/VaultControllerTests.java @@ -71,7 +71,7 @@ public void testInvalidRequestInDetokenizeMethod() { } catch (SkyflowException e) { Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); Assert.assertEquals( - Utils.parameterizedString(ErrorMessage.InvalidDataTokens.getMessage(), Constants.SDK_PREFIX), + Utils.parameterizedString(ErrorMessage.InvalidDetokenizeData.getMessage(), Constants.SDK_PREFIX), e.getMessage() ); } diff --git a/src/test/java/com/skyflow/vault/tokens/DetokenizeTests.java b/src/test/java/com/skyflow/vault/tokens/DetokenizeTests.java index 722a6c59..aea06095 100644 --- a/src/test/java/com/skyflow/vault/tokens/DetokenizeTests.java +++ b/src/test/java/com/skyflow/vault/tokens/DetokenizeTests.java @@ -60,7 +60,7 @@ public void testNoTokensInDetokenizeRequestValidations() { } catch (SkyflowException e) { Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); Assert.assertEquals( - Utils.parameterizedString(ErrorMessage.InvalidDataTokens.getMessage(), Constants.SDK_PREFIX), + Utils.parameterizedString(ErrorMessage.InvalidDetokenizeData.getMessage(), Constants.SDK_PREFIX), e.getMessage() ); Assert.assertFalse(request.getContinueOnError()); @@ -77,7 +77,7 @@ public void testEmptyTokensInDetokenizeRequestValidations() { } catch (SkyflowException e) { Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); Assert.assertEquals( - Utils.parameterizedString(ErrorMessage.EmptyDataTokens.getMessage(), Constants.SDK_PREFIX), + Utils.parameterizedString(ErrorMessage.EmptyDetokenizeData.getMessage(), Constants.SDK_PREFIX), e.getMessage() ); Assert.assertFalse(request.getContinueOnError()); @@ -86,7 +86,7 @@ public void testEmptyTokensInDetokenizeRequestValidations() { } @Test - public void testEmptyTokenInTokensInDetokenizeRequestValidations() { + public void testEmptyTokenInDetokenizeRequestValidations() { DetokenizeData detokenizeDataRecord = new DetokenizeData(""); detokenizeData.add(maskedRedactionRecord); detokenizeData.add(detokenizeDataRecord); @@ -98,7 +98,7 @@ public void testEmptyTokenInTokensInDetokenizeRequestValidations() { } catch (SkyflowException e) { Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); Assert.assertEquals( - Utils.parameterizedString(ErrorMessage.EmptyTokenInDataTokens.getMessage(), Constants.SDK_PREFIX), + Utils.parameterizedString(ErrorMessage.EmptyTokenInDetokenizeData.getMessage(), Constants.SDK_PREFIX), e.getMessage() ); Assert.assertFalse(request.getContinueOnError()); @@ -107,7 +107,7 @@ public void testEmptyTokenInTokensInDetokenizeRequestValidations() { } @Test - public void testNullTokenInTokensInDetokenizeRequestValidations() { + public void testNullTokenInDetokenizeRequestValidations() { DetokenizeData detokenizeDataRecord = new DetokenizeData(null); detokenizeData.add(maskedRedactionRecord); detokenizeData.add(detokenizeDataRecord); @@ -119,7 +119,7 @@ public void testNullTokenInTokensInDetokenizeRequestValidations() { } catch (SkyflowException e) { Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); Assert.assertEquals( - Utils.parameterizedString(ErrorMessage.EmptyTokenInDataTokens.getMessage(), Constants.SDK_PREFIX), + Utils.parameterizedString(ErrorMessage.EmptyTokenInDetokenizeData.getMessage(), Constants.SDK_PREFIX), e.getMessage() ); Assert.assertFalse(request.getContinueOnError()); From 6f64d7a957746101fe79052c95c677884b7e766e Mon Sep 17 00:00:00 2001 From: skyflow-vivek Date: Fri, 14 Feb 2025 19:53:20 +0530 Subject: [PATCH 3/9] SK-1893 Update README for v2 --- README.md | 2101 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 1343 insertions(+), 758 deletions(-) diff --git a/README.md b/README.md index 5ed7d604..1f6563b9 100644 --- a/README.md +++ b/README.md @@ -8,63 +8,74 @@ The Skyflow Java SDK is designed to help with integrating Skyflow into a Java ba # Table of Contents -- [Skyflow Java](#skyflow-java) - [Table of Contents](#table-of-contents) - - [Features](#features) - - [Installation](#installation) - - [Requirements](#requirements) - - [Configuration](#configuration) - - [Gradle users](#gradle-users) - - [Maven users](#maven-users) - - [Service Account Bearer Token Generation](#service-account-bearer-token-generation) - - [Service Account Bearer Token with Context Generation](#service-account-bearer-token-with-context-generation) - - [Service Account Scoped Bearer Token Generation](#service-account-scoped-bearer-token-generation) - - [Signed Data Tokens Generation](#signed-data-tokens-generation) - - [Migrate from v1 to v2](#migrate-from-v1-to-v2) - - [Vault APIs](#vault-apis) - - [Insert](#insert-data-into-the-vault) - - [Detokenize](#detokenize) - - [Get](#get) - - [Use Skyflow IDs](#get-by-skyflow-ids) - - [Use column name and values](#get-by-column-name-and-column-values) - - [Redaction types](#redaction-types) - - [Update](#update) - - [Delete](#delete) - - [Query](#query) - - [Connections](#connections) - - [Invoke Connection](#invoke-connection) - - [Logging](#logging) - - [Reporting a Vulnerability](#reporting-a-vulnerability) - -## Features - -- Authentication with a Skyflow Service Account and generation of a bearer token -- Vault API operations to insert, retrieve and tokenize sensitive data -- Invoking connections to call downstream third party APIs without directly handling sensitive data - -## Installation - -### Requirements - -- Java 1.8 and above - -### Configuration +- [Overview](#overview) +- [Install](#install) + - [Requirements](#requirements) + - [Configuration](#configuration) + - [Gradle users](#gradle-users) + - [Maven users](#maven-users) +- [Migration from v1 to v2](#migration-from-v1-to-v2) + - [Authentication options](#authentication-options) + - [Initializing the client](#initializing-the-client) + - [Request & response structure](#request--response-structure) + - [Request options](#request-options) + - [Error structure](#error-structure) +- [Quickstart](#quickstart) + - [Authenticate](#authenticate) + - [Initialize the client](#initialize-the-client) + - [Insert data into the vault](#insert-data-into-the-vault) +- [Vault](#vault) + - [Insert data into the vault](#insert-data-into-the-vault-1) + - [Detokenize](#detokenize) + - [Tokenize](#tokenize) + - [Get](#get) + - [Get by skyflow IDS](#get-by-skyflow-ids) + - [Get tokens](#get-tokens) + - [Get by column name and column values](#get-by-column-name-and-column-values) + - [Redaction types](#redaction-types) + - [Update](#update) + - [Delete](#delete) + - [Query](#query) +- [Connections](#connections) + - [Invoke a connection](#invoke-a-connection) +- [Authenticate with bearer tokens](#authenticate-with-bearer-tokens) + - [Generate a bearer token](#generate-a-bearer-token) + - [Generate bearer tokens with context](#generate-bearer-tokens-with-context) + - [Generate scoped bearer tokens](#generate-scoped-bearer-tokens) + - [Generate signed data tokens](#generate-signed-data-tokens) +- [Logging](#logging) +- [Reporting a Vulnerability](#reporting-a-vulnerability) + +# Overview + +- Authenticate using a Skyflow service account and generate bearer tokens for secure access. +- Perform Vault API operations such as inserting, retrieving, and tokenizing sensitive data with ease. +- Invoke connections to third-party APIs without directly handling sensitive data, ensuring compliance and data protection. + +# Install + +## Requirements + +- Java 8 and above (tested with Java 8) + +## Configuration + --- -#### Gradle users +### Gradle users -Add this dependency to your project's build file: +Add this dependency to your project's `build.gradle` file: ``` implementation 'com.skyflow:skyflow-java:2.0.0' ``` -#### Maven users +### Maven users -Add this dependency to your project's POM: +Add this dependency to your project's `pom.xml` file: ```xml - com.skyflow skyflow-java @@ -74,250 +85,24 @@ Add this dependency to your project's POM: --- -## Service Account Bearer Token Generation - -The [Service Account](https://github.com/skyflowapi/skyflow-java/tree/main/src/main/java/com/skyflow/serviceaccount/util) -java module is used to generate service account tokens from service account credentials file which is downloaded upon -creation of service account. The token generated from this module is valid for 60 minutes and can be used to make API -calls to vault services as well as management API(s) based on the permissions of the service account. - -The `BearerToken` utility class allows to generate bearer token with the help of credentials json file. Alternatively, -you can also send the entire credentials as a string. - -[Example](https://github.com/skyflowapi/skyflow-java/blob/main/samples/src/main/java/com/example/serviceaccount/BearerTokenGenerationExample.java -): - -```java -import com.skyflow.errors.SkyflowException; -import com.skyflow.serviceaccount.util.BearerToken; -import com.skyflow.serviceaccount.util.Token; - -import java.io.File; - -public class BearerTokenGenerationExample { - public static void main(String[] args) { - String token = null; - // Generate BearerToken by specifying credentials.json file path - try { - String filePath = ""; - if (Token.isExpired(token)) { - BearerToken bearerToken = BearerToken.builder().setCredentials(new File(filePath)).build(); - token = bearerToken.getBearerToken(); - } - System.out.println(token); - } catch (SkyflowException e) { - e.printStackTrace(); - } - - // Generate BearerToken by specifying credentials.json as string - try { - String fileContents = ""; - if (Token.isExpired(token)) { - BearerToken bearerToken = BearerToken.builder().setCredentials(fileContents).build(); - token = bearerToken.getBearerToken(); - } - System.out.println(token); - } catch (SkyflowException e) { - e.printStackTrace(); - } - } -} -``` - -## Service Account Bearer Token with Context Generation - -Context-Aware Authorization enables you to embed context values into a Bearer token when you generate it, and reference -those values in your policies for more dynamic access control of data in the vault or validating signed data tokens -during detokenization. It can be used to track end user identity when making API calls using service accounts. - -The service account generated with `context_id` identifier enabled can be used to generate bearer tokens with `context`, -which is a `jwt` claim for a skyflow generated bearer token. The token generated from this service account will have a -`context_identifier` claim and is valid for 60 minutes and can be used to make API calls to vault services as well as -management API(s) based on the permissions of the service account. - -[Example](https://github.com/skyflowapi/skyflow-java/blob/main/samples/src/main/java/com/example/serviceaccount/BearerTokenGenerationWithContextExample.java): - -``` java -import com.skyflow.errors.SkyflowException; -import com.skyflow.serviceaccount.util.BearerToken; - -import java.io.File; - -public class BearerTokenGenerationWithContextExample { - public static void main(String[] args) { - String bearerToken = null; - // Generate BearerToken with context by specifying credentials.json file path - try { - String filePath = ""; - BearerToken token = BearerToken.builder() - .setCredentials(new File(filePath)) - .setCtx("abc") - .build(); - - bearerToken = token.getBearerToken(); - System.out.println(bearerToken); - } catch (SkyflowException e) { - e.printStackTrace(); - } - - // Generate BearerToken with context by specifying credentials.json as string - try { - String fileContents = ""; - BearerToken token = BearerToken.builder() - .setCredentials(fileContents) - .setCtx("abc") - .build(); - - bearerToken = token.getBearerToken(); - System.out.println(bearerToken); - } catch (SkyflowException e) { - e.printStackTrace(); - } - } -} -``` - -## Service Account Scoped Bearer Token Generation - -A service account that has multiple roles can generate bearer tokens with access restricted to a specific role by -providing the appropriate `roleID`. Generated bearer tokens are valid for 60 minutes and can only perform operations -with the permissions associated with the specified role. - -[Example](https://github.com/skyflowapi/skyflow-java/blob/main/samples/src/main/java/com/example/serviceaccount/ScopedTokenGenerationExample.java): - -```java -import com.skyflow.errors.SkyflowException; -import com.skyflow.serviceaccount.util.BearerToken; - -import java.io.File; -import java.util.ArrayList; - -public class ScopedTokenGenerationExample { - public static void main(String[] args) { - String scopedToken = null; - // Generate Scoped Token by specifying credentials.json file path - try { - ArrayList roles = new ArrayList<>(); - roles.add("ROLE_ID"); - String filePath = ""; - BearerToken bearerToken = BearerToken.builder() - .setCredentials(new File(filePath)) - .setRoles(roles) - .build(); - - scopedToken = bearerToken.getBearerToken(); - System.out.println(scopedToken); - } catch (SkyflowException e) { - e.printStackTrace(); - } - } -} -``` - -Notes: - -- You can pass either a service account key credentials file path or a service account key credentials as string to the - `setCredentials` method of the BearerTokenBuilder class. -- If you pass both a file path and string to the `setCredentials` method, the last method used takes precedence. -- To generate multiple bearer tokens using a thread, see - this [example](https://github.com/skyflowapi/skyflow-java/blob/main/samples/src/main/java/com/example/serviceaccount/BearerTokenGenerationUsingThreadsExample.java) - -## Signed Data Tokens Generation - -Skyflow generates data tokens when sensitive data is inserted into the vault. These data tokens can be digitally signed -with the private key of the service account credentials, which adds an additional layer of protection. Signed tokens can -be detokenized by passing the signed data token and a bearer token generated from service account credentials. The -service account must have appropriate permissions and context to detokenize the signed data tokens. - -[Example](https://github.com/skyflowapi/skyflow-java/blob/main/samples/src/main/java/com/example/serviceaccount/SignedTokenGenerationExample.java): - -``` java -import com.skyflow.errors.SkyflowException; -import com.skyflow.serviceaccount.util.SignedDataTokenResponse; -import com.skyflow.serviceaccount.util.SignedDataTokens; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; - -public class SignedTokenGenerationExample { - public static void main(String[] args) { - List signedTokenValues; - // Generate Signed data token with context by specifying credentials.json file path - try { - String filePath = ""; - String context = "abc"; - ArrayList dataTokens = new ArrayList<>(); - dataTokens.add("YOUR_DATA_TOKEN_1"); - SignedDataTokens signedToken = SignedDataTokens.builder() - .setCredentials(new File(filePath)) - .setCtx(context) - .setTimeToLive(30) // in seconds - .setDataTokens(dataTokens) - .build(); - signedTokenValues = signedToken.getSignedDataTokens(); - System.out.println(signedTokenValues); - } catch (SkyflowException e) { - e.printStackTrace(); - } - - // Generate Signed data token with context by specifying credentials.json as string - try { - String fileContents = ""; - String context = "abc"; - ArrayList dataTokens = new ArrayList<>(); - dataTokens.add("YOUR_DATA_TOKEN_1"); - SignedDataTokens signedToken = SignedDataTokens.builder() - .setCredentials(fileContents) - .setCtx(context) - .setTimeToLive(30) // in seconds - .setDataTokens(dataTokens) - .build(); - signedTokenValues = signedToken.getSignedDataTokens(); - System.out.println(signedTokenValues); - } catch (SkyflowException e) { - e.printStackTrace(); - } - } -} -``` - -Response: - -``` java -[ - { - "dataToken":"5530-4316-0674-5748", - "signedDataToken":"signed_token_eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJzLCpZjA" - } -] -``` - -Notes: - -- You can pass either a service account key credentials file path or a service account key credentials as string to the - `setCredentials` method of the SignedDataTokensBuilder class. -- If you pass both a file path and string to the `setCredentials` method, the last method used takes precedence. -- Time to live value expects time as seconds. -- The default time to live value is 60 seconds. - -## Migrate from v1 to v2 +# Migrate from v1 to v2 Below are the steps to migrate the java sdk from v1 to v2. -### 1. Authentication Options -In V2, we have introduced multiple authentication options. -You can now provide credentials in the following ways: +### Authentication options -- **API Key (Recommended)** -- **Passing credentials as ENV.** (`SKYFLOW_CREDENTIALS`) (**Recommended**) -- **Path to your credentials JSON file** -- **Stringified JSON of your credentials** -- **Bearer token** +In V2, we have introduced multiple authentication options. You can now provide credentials in the following ways: + +- Passing credentials in ENV. (`SKYFLOW_CREDENTIALS`) _(Recommended)_ +- API Key +- Path to your credentials JSON file +- Stringified JSON of your credentials +- Bearer token These options allow you to choose the authentication method that best suits your use case. -### V1 (Old) +**V1 (Old)** + ```java static class DemoTokenProvider implements TokenProvider { @Override @@ -334,7 +119,8 @@ static class DemoTokenProvider implements TokenProvider { } ``` -### V2 (New): Passing one of the following: +**V2 (New): Passing one of the following:** + ```java // Option 1: API Key (Recommended) Credentials skyflowCredentials = new Credentials(); @@ -353,25 +139,25 @@ skyflowCredentials.setCredentialsString(""); // Replace skyflowCredentials.setToken(""); // Replace with your actual authentication token. ``` -**Notes:** +Notes: + - Use only ONE authentication method. -- API Key or Environment Variables are recommended for production use. +- API Key or environment variables are recommended for production use. - Secure storage of credentials is essential. -- For overriding behavior and priority order of credentials, refer to the README. +- For overriding behavior and priority order of credentials, please refer to [Initialize the client](#initialize-the-client) section in [Quickstart](#quickstart). --- -### 2. Client Initialization -In V2, we have introduced a Builder design pattern for client initialization and added support for multi-vault. This allows you to configure multiple vaults during client initialization. +### Initializing the client -In V2, the log level is tied to each individual client instance. +In V2, we have introduced a builder design pattern for client initialization and added support for multi-vault. This allows you to configure multiple vaults during client initialization. In V2, the log level is tied to each individual client instance. During client initialization, you can pass the following parameters: -During client initialization, you can pass the following parameters: -- `vaultId` and `clusterId`: These values are derived from the vault ID & vault URL. -- `env`: Specify the environment (e.g., SANDBOX or PROD). +- `vaultId` and `clusterId`: These values are derived from the vault ID & vault URL. +- `env`: Specify the environment (e.g., SANDBOX or PROD). - `credentials`: The necessary authentication credentials. -### V1 (Old) +**V1 (Old)** + ```java // DemoTokenProvider class is an implementation of the TokenProvider interface DemoTokenProvider demoTokenProvider = new DemoTokenProvider(); @@ -379,7 +165,8 @@ SkyflowConfiguration skyflowConfig = new SkyflowConfiguration("",""); // Replace with the path to the credentials file @@ -404,19 +191,24 @@ Skyflow skyflowClient = Skyflow.builder() ``` **Key Changes:** + - `vaultUrl` replaced with `clusterId`. - Added environment specification (`env`). - Instance-specific log levels. --- -### 3. Request & Response Structure -In V2, we have removed the use of JSON objects from a third-party package. Instead, we have transitioned to accepting native ArrayList and HashMap data structures and adopted the Builder pattern for request creation. This request need -- `table`: The name of the table. -- `values`: An array of objects containing the data to be inserted. -The response will be of type InsertResponse class, which contains insertedFields and errors. +### Request & response structure + +In V2, we have removed the use of JSON objects from a third-party package. Instead, we have transitioned to accepting native ArrayList and HashMap data structures and adopted the builder pattern for request creation. This request needs: + +- `table`: The name of the table. +- `values`: An array list of objects containing the data to be inserted. + +The response will be of type `InsertResponse` class, which contains `insertedFields` and `errors`. + +**V1 (Old):** Request building -### V1 (Old) Request Building ```java JSONObject recordsJson = new JSONObject(); JSONArray recordsArrayJson = new JSONArray(); @@ -439,7 +231,8 @@ try { } ``` -### V2 (New) Request Building +**V2 (New):** Request building + ```java ArrayList> values = new ArrayList<>(); HashMap value = new HashMap<>(); @@ -462,7 +255,8 @@ InsertRequest insertRequest = InsertRequest.builder() .build(); ``` -### V1 (Old) Response Structure +**V1 (Old):** Response structure + ```json { "records": [ @@ -478,7 +272,8 @@ InsertRequest insertRequest = InsertRequest.builder() } ``` -### V2 (New) Response Structure +**V2 (New):** Response structure + ```json { "insertedFields": [ @@ -495,16 +290,18 @@ InsertRequest insertRequest = InsertRequest.builder() --- -## 4. Request Options -In V2, with the introduction of the Builder design pattern has made handling optional fields in Java more efficient and straightforward. +### Request options + +In V2, with the introduction of the builder design pattern has made handling optional fields in Java more efficient and straightforward. +**V1 (Old)** -### V1 (Old) ```java InsertOptions insertOptions = new InsertOptions(true); ``` -### V2 (New) +**V2 (New)** + ```java InsertRequest upsertRequest = new InsertRequest.builder() .table("") // Replace with the table name @@ -518,40 +315,69 @@ InsertRequest upsertRequest = new InsertRequest.builder() --- -## 5. Enhanced Error Details -The V2 error response includes: +### Error structure + +In V2, we have enriched the error details to provide better debugging capabilities. +The error response now includes: - `httpStatus`: The HTTP status code. - `grpcCode`: The gRPC code associated with the error. - `details` & `message`: A detailed description of the error. - `requestId`: A unique request identifier for easier debugging. -### V1 (Old) Error Structure +**V1 (Old):** Error structure + ```json { - "code": "", - "description": "" + "code": "", + "description": "" } ``` -### V2 (New) Error Structure -```json +**V2 (New):** Error structure + +```js { - "httpStatus": "", - "grpcCode": "", - "httpCode": "", - "message": "", - "requestId": "", - "details": [ "
" ] + "httpStatus": "", + "grpcCode": , + "httpCode": , + "message": "", + "requestId": "", + "details": ["
"] } ``` -## Vault APIs +# Quickstart + +Get started quickly with the essential steps: authenticate, initialize the client, and perform a basic vault operation. This section provides a minimal setup to help you integrate the SDK efficiently. + +### Authenticate + +You can use an API key to authenticate and authorize requests to an API. For authenticating via bearer tokens and different supported bearer token types, refer to the [Authenticate with bearer tokens](#authenticate-with-bearer-tokens) section. + +```java +// create a new credentials object +Credentials credentials = new Credentials(); +credentials.setApiKey(""); // add your API key in credentials +``` + +### Initialize the client + +To get started, you must first initialize the skyflow client. While initializing the skyflow client, you can specify different types of credentials. + +1. **API keys** + A unique identifier used to authenticate and authorize requests to an API. + +2. **Bearer tokens** + A temporary access token used to authenticate API requests, typically included in the Authorization header. + +3. **Service account credentials file path** + The file path pointing to a JSON file containing credentials for a service account, used for secure API access. -The [Vault](https://github.com/skyflowapi/skyflow-java/tree/main/src/main/java/com/skyflow/vault) module is used to -perform operations on the vault such as inserting records, detokenizing tokens and retrieving tokens for a skyflow_id. +4. **Service account credentials string (JSON formatted)** + A JSON-formatted string containing service account credentials, often used as an alternative to a file for programmatic authentication. -To use this module, the skyflow client must first be initialized as follows. +Note: Only one type of credential can be used at a time. If multiple credentials are provided, the last one added will take precedence. ```java import com.skyflow.Skyflow; @@ -561,52 +387,100 @@ import com.skyflow.enums.Env; import com.skyflow.enums.LogLevel; import com.skyflow.errors.SkyflowException; +/** + * Example program to initialize the Skyflow client with various configurations. + * The Skyflow client facilitates secure interactions with the Skyflow vault, + * such as securely managing sensitive data. + */ public class InitSkyflowClient { public static void main(String[] args) throws SkyflowException { - // Pass only one of apiKey, token, credentialsString or path in credentials - Credentials credentials = new Credentials(); - credentials.setToken(""); - - VaultConfig config = new VaultConfig(); - config.setVaultId(""); // Primary vault - config.setClusterId(""); // ID from your vault URL Eg https://{clusterId}.vault.skyflowapis.com - config.setEnv(Env.PROD); // Env by default is set to PROD - config.setCredentials(credentials); // Individual credentials - + // Step 1: Define the primary credentials for authentication. + // Note: Only one type of credential can be used at a time. You can choose between: + // - API key + // - Bearer token + // - A credentials string (JSON-formatted) + // - A file path to a credentials file. + + // Initialize primary credentials using a Bearer token for authentication. + Credentials primaryCredentials = new Credentials(); + primaryCredentials.setToken(""); // Replace with your actual authentication token. + + // Step 2: Configure the primary vault details. + // VaultConfig stores all necessary details to connect to a specific Skyflow vault. + VaultConfig primaryConfig = new VaultConfig(); + primaryConfig.setVaultId(""); // Replace with your primary vault's ID. + primaryConfig.setClusterId(""); // Replace with the cluster ID (part of the vault URL, e.g., https://{clusterId}.vault.skyflowapis.com). + primaryConfig.setEnv(Env.PROD); // Set the environment (PROD, SANDBOX, STAGE, DEV). + primaryConfig.setCredentials(primaryCredentials); // Attach the primary credentials to this vault configuration. + + // Step 3: Create credentials as a JSON object (if a Bearer Token is not provided). + // Demonstrates an alternate approach to authenticate with Skyflow using a credentials object. JsonObject credentialsObject = new JsonObject(); - credentialsObject.addProperty("clientID", ""); - credentialsObject.addProperty("clientName", ""); - credentialsObject.addProperty("TokenURI", ""); - credentialsObject.addProperty("keyID", ""); - credentialsObject.addProperty("privateKey", ""); - - // To generate Bearer Token from credentials string. + credentialsObject.addProperty("clientID", ""); // Replace with your Client ID. + credentialsObject.addProperty("clientName", ""); // Replace with your Client Name. + credentialsObject.addProperty("TokenURI", ""); // Replace with the Token URI. + credentialsObject.addProperty("keyID", ""); // Replace with your Key ID. + credentialsObject.addProperty("privateKey", ""); // Replace with your Private Key. + + // Step 4: Convert the JSON object to a string and use it as credentials. + // This approach allows the use of dynamically generated or pre-configured credentials. Credentials skyflowCredentials = new Credentials(); - skyflowCredentials.setCredentialsString(credentialsObject.toString()); - + skyflowCredentials.setCredentialsString(credentialsObject.toString()); // Converts JSON object to string for use as credentials. + + // Step 5: Define secondary credentials (API key-based authentication as an example). + // Demonstrates a different type of authentication mechanism for Skyflow vaults. + Credentials secondaryCredentials = new Credentials(); + secondaryCredentials.setApiKey(""); // Replace with your API Key for authentication. + + // Step 6: Configure the secondary vault details. + // A secondary vault configuration can be used for operations involving multiple vaults. + VaultConfig secondaryConfig = new VaultConfig(); + secondaryConfig.setVaultId(""); // Replace with your secondary vault's ID. + secondaryConfig.setClusterId(""); // Replace with the corresponding cluster ID. + secondaryConfig.setEnv(Env.SANDBOX); // Set the environment for this vault. + secondaryConfig.setCredentials(secondaryCredentials); // Attach the secondary credentials to this configuration. + + // Step 7: Define tertiary credentials using a path to a credentials JSON file. + // This method demonstrates an alternative authentication method. + Credentials tertiaryCredentials = new Credentials(); + tertiaryCredentials.setPath(""); // Replace with the path to your credentials file. + + // Step 8: Configure the tertiary vault details. + VaultConfig tertiaryConfig = new VaultConfig(); + tertiaryConfig.setVaultId(""); // Replace with the tertiary vault ID. + tertiaryConfig.setClusterId(""); // Replace with the corresponding cluster ID. + tertiaryConfig.setEnv(Env.STAGE); // Set the environment for this vault. + tertiaryConfig.setCredentials(tertiaryCredentials); // Attach the tertiary credentials. + + // Step 9: Build and initialize the Skyflow client. + // Skyflow client is configured with multiple vaults and credentials. Skyflow skyflowClient = Skyflow.builder() - .setLogLevel(LogLevel.INFO) // Set log level. By default, it is set to ERROR - .addVaultConfig(config) // Add vault config - .addSkyflowCredentials(skyflowCredentials) // Skyflow credentials will be used if no individual credentials are passed + .setLogLevel(LogLevel.INFO) // Set log level for debugging or monitoring purposes. + .addVaultConfig(primaryConfig) // Add the primary vault configuration. + .addVaultConfig(secondaryConfig) // Add the secondary vault configuration. + .addVaultConfig(tertiaryConfig) // Add the tertiary vault configuration. + .addSkyflowCredentials(skyflowCredentials) // Add JSON-formatted credentials if applicable. .build(); + + // The Skyflow client is now fully initialized. + // Use the `skyflowClient` object to perform secure operations such as: + // - Inserting data + // - Retrieving data + // - Deleting data + // within the configured Skyflow vaults. } } ``` Notes: -- If both Skyflow common credentials and individual credentials at the configuration level are provided, the individual - credentials at the configuration level will take priority. - -All Vault APIs must be invoked using a client instance. - -## Insert data into the vault +- If both Skyflow common credentials and individual credentials at the configuration level are specified, the individual credentials at the configuration level will take precedence. +- If neither Skyflow common credentials nor individual configuration-level credentials are provided, the SDK attempts to retrieve credentials from the `SKYFLOW_CREDENTIALS` environment variable. +- All Vault operations require a client instance. -To insert data into your vault, use the `insert` method. The `InsertRequest` class is used to create an insert request, -which contains the values to be inserted in the form of a list of records. Additionally, you can provide options in the -insert request, such as returning tokenized data, upserting records, and continuing on error. +### Insert data into the vault -Insert call schema +To insert data into your vault, use the `insert` method. The `InsertRequest` class creates an insert request, which includes the values to be inserted as a list of records. Below is a simple example to get started. For advanced options, check out [Insert data into the vault](#insert-data-into-the-vault-1) section. ```java import com.skyflow.errors.SkyflowException; @@ -616,36 +490,76 @@ import com.skyflow.vault.data.InsertResponse; import java.util.ArrayList; import java.util.HashMap; -public class InsertSchema { +/** + * This example demonstrates how to insert sensitive data (e.g., card information) into a Skyflow vault using the Skyflow client. + * + * 1. Initializes the Skyflow client. + * 2. Prepares a record with sensitive data (e.g., card number and cardholder name). + * 3. Creates an insert request for inserting the data into the Skyflow vault. + * 4. Prints the response of the insert operation. + */ +public class InsertExample { public static void main(String[] args) { try { - // Initialize skyflow client + // Initialize Skyflow client + // Step 1: Initialize data to be inserted into the Skyflow vault ArrayList> insertData = new ArrayList<>(); - HashMap insertRecord1 = new HashMap<>(); - insertRecord1.put("", ""); - insertRecord1.put("", ""); + // Create a HashMap for a single record with card number and cardholder name as fields + HashMap insertRecord = new HashMap<>(); + insertRecord.put("card_number", "4111111111111111"); // Replace with actual card number (sensitive data) + insertRecord.put("cardholder_name", "john doe"); // Replace with actual cardholder name (sensitive data) - HashMap insertRecord2 = new HashMap<>(); - insertRecord2.put("", ""); - insertRecord2.put("", ""); + // Add the created record to the list of data to be inserted + insertData.add(insertRecord); - insertData.add(insertRecord1); - insertData.add(insertRecord2); + // Step 2: Build the InsertRequest object with the table name and data to insert + InsertRequest insertRequest = InsertRequest.builder() + .table("table1") // Specify the table in the vault where the data will be inserted + .values(insertData) // Attach the data (records) to be inserted + .returnTokens(true) // Specify if tokens should be returned upon successful insertion + .build(); // Build the insert request object - InsertRequest insertRequest = InsertRequest.builder().table("").values(insertData).build(); - InsertResponse insertResponse = skyflowClient.vault("").insert(); - System.out.println("Insert Response: " + insertResponse); + // Step 3: Perform the insert operation using the Skyflow client + InsertResponse insertResponse = skyflowClient.vault("9f27764a10f7946fe56b3258e117").insert(insertRequest); + // Replace the vault ID "9f27764a10f7946fe56b3258e117" with your actual Skyflow vault ID + + // Step 4: Print the response from the insert operation + System.out.println(insertResponse); } catch (SkyflowException e) { + // Step 5: Handle any exceptions that may occur during the insert operation System.out.println("Error occurred: "); - System.out.println(e); + e.printStackTrace(); // Print the stack trace for debugging purposes } } } ``` -Insert -call [example](https://github.com/skyflowapi/skyflow-java/blob/main/samples/src/main/java/com/example/vault/InsertExample.java) +Skyflow returns tokens for the record that was just inserted. + +```json +{ + "insertedFields": [ + { + "card_number": "5484-7829-1702-9110", + "request_index": "0", + "skyflow_id": "9fac9201-7b8a-4446-93f8-5244e1213bd1", + "cardholder_name": "b2308e2a-c1f5-469b-97b7-1f193159399b" + } + ], + "errors": [] +} +``` + +# Vault + +The [Vault](https://github.com/skyflowapi/skyflow-java/tree/main/src/main/java/com/skyflow/vault) module performs operations on the vault, including inserting records, detokenizing tokens, and retrieving tokens associated with a `skyflow_id`. + +## Insert data into the vault + +Apart from using the `insert` method to insert data into your vault covered in [Quickstart](#quickstart), you can also specify options in `InsertRequest`, such as returning tokenized data, upserting records, or continuing the operation in case of errors. + +### Construct an insert request ```java import com.skyflow.errors.SkyflowException; @@ -655,46 +569,55 @@ import com.skyflow.vault.data.InsertResponse; import java.util.ArrayList; import java.util.HashMap; -public class InsertExample { +/** + * Example program to demonstrate inserting data into a Skyflow vault, along with corresponding InsertRequest schema. + * + */ +public class InsertSchema { public static void main(String[] args) { try { - // Initialize skyflow client + // Initialize Skyflow client + // Step 1: Prepare the data to be inserted into the Skyflow vault ArrayList> insertData = new ArrayList<>(); - HashMap insertRecord = new HashMap<>(); - insertRecord.put("card_number", "4111111111111111"); - insertRecord.put("cardholder_name", "john doe"); - insertData.add(insertRecord); + // Create the first record with field names and their respective values + HashMap insertRecord1 = new HashMap<>(); + insertRecord1.put("", ""); // Replace with actual field name and value + insertRecord1.put("", ""); // Replace with actual field name and value + + // Create the second record with field names and their respective values + HashMap insertRecord2 = new HashMap<>(); + insertRecord2.put("", ""); // Replace with actual field name and value + insertRecord2.put("", ""); // Replace with actual field name and value + + // Add the records to the list of data to be inserted + insertData.add(insertRecord1); + insertData.add(insertRecord2); + + // Step 2: Build an InsertRequest object with the table name and the data to insert InsertRequest insertRequest = InsertRequest.builder() - .table("table1") - .values(insertData) - .returnTokens(true) + .table("") // Replace with the actual table name in your Skyflow vault + .values(insertData) // Attach the data to be inserted .build(); - InsertResponse insertResponse = skyflowClient.vault("9f27764a10f7946fe56b3258e117").insert(); + + // Step 3: Use the Skyflow client to perform the insert operation + InsertResponse insertResponse = skyflowClient.vault("").insert(insertRequest); + // Replace with your actual vault ID + + // Print the response from the insert operation System.out.println("Insert Response: " + insertResponse); } catch (SkyflowException e) { - System.out.println("Error occurred: "); - System.out.println(e); + // Step 4: Handle any exceptions that occur during the insert operation + System.out.println("Error occurred while inserting data: "); + e.printStackTrace(); // Print the stack trace for debugging } } } ``` -Skyflow returns tokens for the record you just inserted. +### Insert call [example](https://github.com/skyflowapi/skyflow-java/blob/SK-1893-update-readme-for-v2/samples/src/main/java/com/example/vault/InsertExample.java) with `continueOnError` option -```js -Insert Response: { - "insertedFields": [{ - "card_number": "5484-7829-1702-9110", - "request_index": "0", - "skyflow_id": "9fac9201-7b8a-4446-93f8-5244e1213bd1", - "cardholder_name": "b2308e2a-c1f5-469b-97b7-1f193159399b", - }], - "errors": [] -} -``` - -Insert call example with `continueOnError` option +The `continueOnError` flag is a boolean that determines whether insert operation should proceed despite encountering partial errors. Set to `true` to allow the process to continue even if some errors occur. ```java import com.skyflow.errors.SkyflowException; @@ -704,34 +627,54 @@ import com.skyflow.vault.data.InsertResponse; import java.util.ArrayList; import java.util.HashMap; +/** + * This example demonstrates how to insert multiple records into a Skyflow vault using the Skyflow client. + * + * 1. Initializes the Skyflow client. + * 2. Prepares multiple records with sensitive data (e.g., card number and cardholder name). + * 3. Creates an insert request with the records to insert into the Skyflow vault. + * 4. Specifies options to continue on error and return tokens. + * 5. Prints the response of the insert operation. + */ public class InsertExample { public static void main(String[] args) { try { - // Initialize skyflow client + // Initialize Skyflow client + // Step 1: Initialize a list to hold the data records to be inserted into the vault ArrayList> insertData = new ArrayList<>(); + // Step 2: Create the first record with card number and cardholder name HashMap insertRecord1 = new HashMap<>(); - insertRecord1.put("card_number", "4111111111111111"); - insertRecord1.put("cardholder_name", "john doe"); + insertRecord1.put("card_number", "4111111111111111"); // Replace with actual card number (sensitive data) + insertRecord1.put("cardholder_name", "john doe"); // Replace with actual cardholder name (sensitive data) + // Step 3: Create the second record with card number and cardholder name HashMap insertRecord2 = new HashMap<>(); - insertRecord2.put("card_numbe", "4111111111111111"); - insertRecord2.put("cardholder_name", "jane doe"); + insertRecord2.put("card_number", "4111111111111111"); // Ensure field name matches ("card_number") + insertRecord2.put("cardholder_name", "jane doe"); // Replace with actual cardholder name (sensitive data) + // Step 4: Add the records to the insertData list insertData.add(insertRecord1); insertData.add(insertRecord2); + // Step 5: Build the InsertRequest object with the data records to insert InsertRequest insertRequest = InsertRequest.builder() - .table("table1") - .values(insertData) - .returnTokens(true) - .continueOnError(true) - .build(); - InsertResponse insertResponse = skyflowClient.vault("9f27764a10f7946fe56b3258e117").insert(); - System.out.println("Insert Response: " + insertResponse); + .table("table1") // Specify the table in the vault where data will be inserted + .values(insertData) // Attach the data records to be inserted + .returnTokens(true) // Specify if tokens should be returned upon successful insertion + .continueOnError(true) // Specify to continue inserting records even if an error occurs for some records + .build(); // Build the insert request object + + // Step 6: Perform the insert operation using the Skyflow client + InsertResponse insertResponse = skyflowClient.vault("9f27764a10f7946fe56b3258e117").insert(insertRequest); + // Replace the vault ID "9f27764a10f7946fe56b3258e117" with your actual Skyflow vault ID + + // Step 7: Print the response from the insert operation + System.out.println(insertResponse); } catch (SkyflowException e) { + // Step 8: Handle any exceptions that may occur during the insert operation System.out.println("Error occurred: "); - System.out.println(e); + e.printStackTrace(); // Print the stack trace for debugging purposes } } } @@ -739,22 +682,28 @@ public class InsertExample { Sample response: -```js +```json { - "insertedFields": [{ - "card_number": "5484-7829-1702-9110", - "request_index": "0", - "skyflow_id": "9fac9201-7b8a-4446-93f8-5244e1213bd1", - "cardholder_name": "b2308e2a-c1f5-469b-97b7-1f193159399b", - }], - "errors": [{ - "request_index": "1", - "error": "Insert failed. Column card_numbe is invalid. Specify a valid column.", - }] + "insertedFields": [ + { + "card_number": "5484-7829-1702-9110", + "request_index": "0", + "skyflow_id": "9fac9201-7b8a-4446-93f8-5244e1213bd1", + "cardholder_name": "b2308e2a-c1f5-469b-97b7-1f193159399b" + } + ], + "errors": [ + { + "request_index": "1", + "error": "Insert failed. Column card_numbe is invalid. Specify a valid column." + } + ] } ``` -Insert call example with `upsert` option +### Insert call example with `upsert` option + +An upsert operation checks for a record based on a unique column's value. If a match exists, the record is updated; otherwise, a new record is inserted. ```java import com.skyflow.errors.SkyflowException; @@ -764,26 +713,47 @@ import com.skyflow.vault.data.InsertResponse; import java.util.ArrayList; import java.util.HashMap; -public class InsertExample { +/** + * This example demonstrates how to insert or upsert a record into a Skyflow vault using the Skyflow client, with the option to return tokens. + * + * 1. Initializes the Skyflow client. + * 2. Prepares a record to insert or upsert (e.g., cardholder name). + * 3. Creates an insert request with the data to be inserted or upserted into the Skyflow vault. + * 4. Specifies the field (cardholder_name) for upsert operations. + * 5. Prints the response of the insert or upsert operation. + */ +public class UpsertExample { public static void main(String[] args) { try { - // Initialize skyflow client + // Initialize Skyflow client + // Step 1: Initialize a list to hold the data records for the insert/upsert operation ArrayList> upsertData = new ArrayList<>(); + + // Step 2: Create a record with the field 'cardholder_name' to insert or upsert HashMap upsertRecord = new HashMap<>(); - upsertRecord.put("cardholder_name", "jane doe"); + upsertRecord.put("cardholder_name", "jane doe"); // Replace with the actual cardholder name + + // Step 3: Add the record to the upsertData list upsertData.add(upsertRecord); + // Step 4: Build the InsertRequest object with the upsertData InsertRequest insertRequest = InsertRequest.builder() - .table("table1") - .values(upsertData) - .returnTokens(true) - .upsert("cardholder_name") - .build(); - InsertResponse insertResponse = skyflowClient.vault("9f27764a10f7946fe56b3258e117").insert(); - System.out.println("Insert Response: " + insertResponse); + .table("table1") // Specify the table in the vault where data will be inserted/upserted + .values(upsertData) // Attach the data records to be inserted/upserted + .returnTokens(true) // Specify if tokens should be returned upon successful operation + .upsert("cardholder_name") // Specify the field to be used for upsert operations (e.g., cardholder_name) + .build(); // Build the insert request object + + // Step 5: Perform the insert/upsert operation using the Skyflow client + InsertResponse insertResponse = skyflowClient.vault("9f27764a10f7946fe56b3258e117").insert(insertRequest); + // Replace the vault ID "9f27764a10f7946fe56b3258e117" with your actual Skyflow vault ID + + // Step 6: Print the response from the insert/upsert operation + System.out.println(insertResponse); } catch (SkyflowException e) { + // Step 7: Handle any exceptions that may occur during the insert/upsert operation System.out.println("Error occurred: "); - System.out.println(e); + e.printStackTrace(); // Print the stack trace for debugging purposes } } } @@ -791,21 +761,23 @@ public class InsertExample { Skyflow returns tokens, with `upsert` support, for the record you just inserted. -```js +```json { - "insertedFields": [{ - "skyflowId": "9fac9201-7b8a-4446-93f8-5244e1213bd1", - "cardholder_name": "73ce45ce-20fd-490e-9310-c1d4f603ee83" - }], - "errors": [] + "insertedFields": [ + { + "skyflowId": "9fac9201-7b8a-4446-93f8-5244e1213bd1", + "cardholder_name": "73ce45ce-20fd-490e-9310-c1d4f603ee83" + } + ], + "errors": [] } ``` ## Detokenize -To retrieve tokens from your vault, you can use the `detokenize` method. The `DetokenizeRequest` class requires a list -of detokenization data to be provided as input. Additionally, the redaction type and continue on error are optional -parameters. +To retrieve tokens from your vault, use the `detokenize` method. The `DetokenizeRequest` class requires a list of detokenization data as input. Additionally, you can provide optional parameters, such as the redaction type and the option to continue on error. + +### Construct a detokenize request ```java import com.skyflow.enums.RedactionType; @@ -815,24 +787,37 @@ import com.skyflow.vault.tokens.DetokenizeResponse; import java.util.ArrayList; +/** + * This example demonstrates how to detokenize sensitive data from tokens stored in a Skyflow vault, along with corresponding DetokenizeRequest schema. + * + */ public class DetokenizeSchema { public static void main(String[] args) { try { - // Initialize skyflow client + // Initialize Skyflow client + // Step 1: Initialize a list of tokens to be detokenized (replace with actual tokens) ArrayList tokens = new ArrayList<>(); - tokens.add(""); - tokens.add(""); - tokens.add(""); + tokens.add(""); // Replace with your actual token value + tokens.add(""); // Replace with your actual token value + tokens.add(""); // Replace with your actual token value + + // Step 2: Create the DetokenizeRequest object with the tokens and redaction type DetokenizeRequest detokenizeRequest = DetokenizeRequest.builder() - .tokens(tokens) - .continueOnError(true) - .redactionType(RedactionType.PLAIN_TEXT) - .build(); + .tokens(tokens) // Provide the list of tokens to be detokenized + .continueOnError(true) // Continue even if one token cannot be detokenized + .redactionType(RedactionType.PLAIN_TEXT) // Specify how the detokenized data should be returned (plain text) + .build(); // Build the detokenization request + + // Step 3: Call the Skyflow vault to detokenize the provided tokens DetokenizeResponse detokenizeResponse = skyflowClient.vault("").detokenize(detokenizeRequest); + // Replace with your actual Skyflow vault ID + + // Step 4: Print the detokenization response, which contains the detokenized data System.out.println(detokenizeResponse); } catch (SkyflowException e) { + // Step 5: Handle any errors that occur during the detokenization process System.out.println("Error occurred: "); - System.out.println(e); + e.printStackTrace(); // Print the exception for debugging purposes } } } @@ -843,8 +828,7 @@ Notes: - `redactionType` defaults to [`RedactionType.PLAIN_TEXT`](#redaction-types). - `continueOnError` defaults to `true`. -An [example](https://github.com/skyflowapi/skyflow-java/blob/main/samples/src/main/java/com/example/vault/DetokenizeExample.java) -of a detokenize call: +### An [example](https://github.com/skyflowapi/skyflow-java/blob/main/samples/src/main/java/com/example/vault/DetokenizeExample.java) of a detokenize call: ```java import com.skyflow.enums.RedactionType; @@ -854,24 +838,42 @@ import com.skyflow.vault.tokens.DetokenizeResponse; import java.util.ArrayList; +/** + * This example demonstrates how to detokenize sensitive data from tokens stored in a Skyflow vault. + * + * 1. Initializes the Skyflow client. + * 2. Creates a list of tokens (e.g., credit card tokens) that represent the sensitive data. + * 3. Builds a detokenization request using the provided tokens and specifies how the redacted data should be returned. + * 4. Calls the Skyflow vault to detokenize the tokens and retrieves the detokenized data. + * 5. Prints the detokenization response, which contains the detokenized values or errors. + */ public class DetokenizeExample { public static void main(String[] args) { try { - // Initialize skyflow client + // Initialize Skyflow client + // Step 1: Initialize a list of tokens to be detokenized (replace with actual token values) ArrayList tokens = new ArrayList<>(); - tokens.add("9738-1683-0486-1480"); - tokens.add("6184-6357-8409-6668"); - tokens.add("4914-9088-2814-3840"); + tokens.add("9738-1683-0486-1480"); // Replace with your actual token value + tokens.add("6184-6357-8409-6668"); // Replace with your actual token value + tokens.add("4914-9088-2814-3840"); // Replace with your actual token value + + // Step 2: Create the DetokenizeRequest object with the tokens and redaction type DetokenizeRequest detokenizeRequest = DetokenizeRequest.builder() - .tokens(tokens) - .continueOnError(false) - .redactionType(RedactionType.PLAIN_TEXT) - .build(); + .tokens(tokens) // Provide the list of tokens to be detokenized + .continueOnError(false) // Stop the process if any token cannot be detokenized + .redactionType(RedactionType.PLAIN_TEXT) // Specify how the detokenized data should be returned (plain text) + .build(); // Build the detokenization request + + // Step 3: Call the Skyflow vault to detokenize the provided tokens DetokenizeResponse detokenizeResponse = skyflowClient.vault("9f27764a10f7946fe56b3258e117").detokenize(detokenizeRequest); + // Replace "9f27764a10f7946fe56b3258e117" with your actual Skyflow vault ID + + // Step 4: Print the detokenization response, which contains the detokenized data System.out.println(detokenizeResponse); } catch (SkyflowException e) { + // Step 5: Handle any errors that occur during the detokenization process System.out.println("Error occurred: "); - System.out.println(e); + e.printStackTrace(); // Print the exception for debugging purposes } } } @@ -879,7 +881,7 @@ public class DetokenizeExample { Sample response: -```js +```json { "detokenizedFields": [{ "token": "9738-1683-0486-1480", @@ -899,7 +901,7 @@ Sample response: ``` -An example of a detokenize call with `continueOnError` option: +### An example of a detokenize call with `continueOnError` option: ```java import com.skyflow.enums.RedactionType; @@ -909,24 +911,42 @@ import com.skyflow.vault.tokens.DetokenizeResponse; import java.util.ArrayList; +/** + * This example demonstrates how to detokenize sensitive data (e.g., credit card numbers) from tokens in a Skyflow vault. + * + * 1. Initializes the Skyflow client. + * 2. Creates a list of tokens (e.g., credit card tokens) to be detokenized. + * 3. Builds a detokenization request with the tokens and specifies the redaction type for the detokenized data. + * 4. Calls the Skyflow vault to detokenize the tokens and retrieves the detokenized data. + * 5. Prints the detokenization response, which includes the detokenized values or errors. + */ public class DetokenizeExample { public static void main(String[] args) { try { - // Initialize skyflow client + // Initialize Skyflow client + // Step 1: Initialize a list of tokens to be detokenized (replace with actual token values) ArrayList tokens = new ArrayList<>(); - tokens.add("9738-1683-0486-1480"); - tokens.add("6184-6357-8409-6668"); - tokens.add("4914-9088-2814-384"); + tokens.add("9738-1683-0486-1480"); // Example token value 1 + tokens.add("6184-6357-8409-6668"); // Example token value 2 + tokens.add("4914-9088-2814-384"); // Example token value 3 + + // Step 2: Create the DetokenizeRequest object with the tokens and redaction type DetokenizeRequest detokenizeRequest = DetokenizeRequest.builder() - .tokens(tokens) - .continueOnError(true) - .redactionType(RedactionType.PLAIN_TEXT) - .build(); + .tokens(tokens) // Provide the list of tokens to detokenize + .continueOnError(true) // Continue even if some tokens cannot be detokenized + .redactionType(RedactionType.PLAIN_TEXT) // Specify the format for the detokenized data (plain text) + .build(); // Build the detokenization request + + // Step 3: Call the Skyflow vault to detokenize the provided tokens DetokenizeResponse detokenizeResponse = skyflowClient.vault("9f27764a10f7946fe56b3258e117").detokenize(detokenizeRequest); + // Replace "9f27764a10f7946fe56b3258e117" with your actual Skyflow vault ID + + // Step 4: Print the detokenization response, which contains the detokenized data or errors System.out.println(detokenizeResponse); } catch (SkyflowException e) { + // Step 5: Handle any errors that occur during the detokenization process System.out.println("Error occurred: "); - System.out.println(e); + e.printStackTrace(); // Print the exception for debugging purposes } } } @@ -934,7 +954,7 @@ public class DetokenizeExample { Sample response: -```js +```json { "detokenizedFields": [{ "token": "9738-1683-0486-1480", @@ -954,11 +974,11 @@ Sample response: ## Tokenize -To tokenize data, use the `tokenize` method. The `TokenizeRequest` class is utilized to create a tokenize request. In -this request, you specify the `values` parameter, which is a list of `ColumnValue`. Each `ColumnValue` contains two -properties: `value` and `columnGroup`. +Tokenization replaces sensitive data with unique identifier tokens. This approach protects sensitive information by securely storing the original data while allowing the use of tokens within your application. + +To tokenize data, use the `tokenize` method. The `TokenizeRequest` class creates a tokenize request. In this request, you specify the `values` parameter, which is a list of `ColumnValue` objects. Each `ColumnValue` contains two properties: `value` and `columnGroup`. -Tokenize Schema +### Construct a tokenize request ```java import com.skyflow.errors.SkyflowException; @@ -968,31 +988,44 @@ import com.skyflow.vault.tokens.TokenizeResponse; import java.util.ArrayList; +/** + * This example demonstrates how to tokenize sensitive data (e.g., credit card information) using the Skyflow client, along with corresponding TokenizeRequest schema. + * + */ public class TokenizeSchema { public static void main(String[] args) { try { - // Initialize Skyflow client + // Initialize Skyflow client + // Step 1: Initialize a list of column values to be tokenized (replace with actual sensitive data) ArrayList columnValues = new ArrayList<>(); - ColumnValue columnValue1 = ColumnValue.builder().value("").columnGroup("").build(); - ColumnValue columnValue2 = ColumnValue.builder().value("").columnGroup("").build(); + // Step 2: Create column values for each sensitive data field (e.g., card number and cardholder name) + ColumnValue columnValue1 = ColumnValue.builder().value("").columnGroup("").build(); // Replace and with actual data + ColumnValue columnValue2 = ColumnValue.builder().value("").columnGroup("").build(); // Replace and with actual data + // Add the created column values to the list columnValues.add(columnValue1); columnValues.add(columnValue2); + // Step 3: Build the TokenizeRequest with the column values TokenizeRequest tokenizeRequest = TokenizeRequest.builder().values(columnValues).build(); + + // Step 4: Call the Skyflow vault to tokenize the sensitive data TokenizeResponse tokenizeResponse = skyflowClient.vault("").tokenize(tokenizeRequest); + // Replace with your actual Skyflow vault ID + + // Step 5: Print the tokenization response, which contains the generated tokens or errors System.out.println(tokenizeResponse); } catch (SkyflowException e) { + // Step 6: Handle any errors that occur during the tokenization process System.out.println("Error occurred: "); - System.out.println(e); + e.printStackTrace(); // Print the exception for debugging purposes } } } ``` -An [example](https://github.com/skyflowapi/skyflow-java/blob/main/samples/src/main/java/com/example/vault/TokenizeExample.java) -of Tokenize call: +### An [example](https://github.com/skyflowapi/skyflow-java/blob/main/samples/src/main/java/com/example/vault/TokenizeExample.java) of Tokenize call: ```java import com.skyflow.errors.SkyflowException; @@ -1002,20 +1035,44 @@ import com.skyflow.vault.tokens.TokenizeResponse; import java.util.ArrayList; -public class TokenizeSchema { +/** + * This example demonstrates how to tokenize sensitive data (e.g., credit card information) using the Skyflow client. + * + * 1. Initializes the Skyflow client. + * 2. Creates a column value for sensitive data (e.g., credit card number). + * 3. Builds a tokenize request with the column value to be tokenized. + * 4. Sends the request to the Skyflow vault for tokenization. + * 5. Prints the tokenization response, which includes the token or errors. + */ +public class TokenizeExample { public static void main(String[] args) { try { - // Initialize Skyflow client + // Initialize Skyflow client + // Step 1: Initialize a list of column values to be tokenized (replace with actual sensitive data) ArrayList columnValues = new ArrayList<>(); - ColumnValue columnValue = ColumnValue.builder().value("4111111111111111").columnGroup("card_number_cg").build(); + + // Step 2: Create a column value for the sensitive data (e.g., card number with its column group) + ColumnValue columnValue = ColumnValue.builder() + .value("4111111111111111") // Replace with the actual sensitive data (e.g., card number) + .columnGroup("card_number_cg") // Replace with the actual column group name + .build(); + + // Add the created column value to the list columnValues.add(columnValue); + // Step 3: Build the TokenizeRequest with the column value TokenizeRequest tokenizeRequest = TokenizeRequest.builder().values(columnValues).build(); + + // Step 4: Call the Skyflow vault to tokenize the sensitive data TokenizeResponse tokenizeResponse = skyflowClient.vault("9f27764a10f7946fe56b3258e117").tokenize(tokenizeRequest); + // Replace "9f27764a10f7946fe56b3258e117" with your actual Skyflow vault ID + + // Step 5: Print the tokenization response, which contains the generated token or any errors System.out.println(tokenizeResponse); } catch (SkyflowException e) { + // Step 6: Handle any errors that occur during the tokenization process System.out.println("Error occurred: "); - System.out.println(e); + e.printStackTrace(); // Print the exception for debugging purposes } } } @@ -1023,7 +1080,7 @@ public class TokenizeSchema { Sample response: -```js +```json { "tokens": [5479-4229-4622-1393] } @@ -1031,12 +1088,9 @@ Sample response: ## Get -To retrieve data using Skyflow IDs or unique column values, use the `get` method. The `GetRequest` class is used to -create a get request, where you specify parameters such as the table name, redaction type, Skyflow IDs, column names, -column values, and return tokens. If Skyflow IDs are provided, column names and column values cannot be used. Similarly, -if column names or column values are provided, Skyflow IDs cannot be used. +To retrieve data using Skyflow IDs or unique column values, use the `get` method. The `GetRequest` class creates a get request, where you specify parameters such as the table name, redaction type, Skyflow IDs, column names, column values, and whether to return tokens. If you specify Skyflow IDs, you can't use column names and column values, and the inverse is true—if you specify column names and column values, you can't use Skyflow IDs. -Get Schema +### Construct a get request ```java import com.skyflow.enums.RedactionType; @@ -1046,44 +1100,61 @@ import com.skyflow.vault.data.GetResponse; import java.util.ArrayList; +/** + * This example demonstrates how to retrieve data from the Skyflow vault using different methods, along with corresponding GetRequest schema. + * + */ public class GetSchema { public static void main(String[] args) { try { - // Initialize Skyflow client + // Initialize Skyflow client + // Step 1: Initialize a list of Skyflow IDs to retrieve records (replace with actual Skyflow IDs) ArrayList ids = new ArrayList<>(); - ids.add(""); - ids.add(""); + ids.add(""); // Replace with actual Skyflow ID + ids.add(""); // Replace with actual Skyflow ID + + // Step 2: Create a GetRequest to retrieve records by Skyflow ID without returning tokens GetRequest getByIdRequest = GetRequest.builder() .ids(ids) - .table("") - .returnTokens(false) - .redactionType(RedactionType.PLAIN_TEXT) + .table("") // Replace with the actual table name + .returnTokens(false) // Set to false to avoid returning tokens + .redactionType(RedactionType.PLAIN_TEXT) // Redact data as plain text .build(); - GetResponse getByIdResponse = skyflowClient.vault("").get(getByIdRequest); + + // Send the request to the Skyflow vault and retrieve the records + GetResponse getByIdResponse = skyflowClient.vault("").get(getByIdRequest); // Replace with actual Vault ID System.out.println(getByIdResponse); + // Step 3: Create another GetRequest to retrieve records by Skyflow ID with tokenized values GetRequest getTokensRequest = GetRequest.builder() .ids(ids) - .table("") - .returnTokens(true) + .table("") // Replace with the actual table name + .returnTokens(true) // Set to true to return tokenized values .build(); - GetResponse getTokensResponse = skyflowClient.vault("").get(getTokensRequest); + + // Send the request to the Skyflow vault and retrieve the tokenized records + GetResponse getTokensResponse = skyflowClient.vault("").get(getTokensRequest); // Replace with actual Vault ID System.out.println(getTokensResponse); + // Step 4: Create a GetRequest to retrieve records based on specific column values ArrayList columnValues = new ArrayList<>(); - columnValues.add(""); - columnValues.add(""); + columnValues.add(""); // Replace with the actual column value + columnValues.add(""); // Replace with the actual column value + GetRequest getByColumnRequest = GetRequest.builder() - .table("") - .columnName("") - .columnValues(columnValues) - .redactionType(RedactionType.PLAIN_TEXT) + .table("") // Replace with the actual table name + .columnName("") // Replace with the column name + .columnValues(columnValues) // Add the list of column values to filter by + .redactionType(RedactionType.PLAIN_TEXT) // Redact data as plain text .build(); - GetResponse getByColumnResponse = skyflowClient.vault("").get(getByColumnRequest); + + // Send the request to the Skyflow vault and retrieve the records filtered by column values + GetResponse getByColumnResponse = skyflowClient.vault("").get(getByColumnRequest); // Replace with actual Vault ID System.out.println(getByColumnResponse); } catch (SkyflowException e) { + // Step 5: Handle any errors that occur during the retrieval process System.out.println("Error occurred: "); - System.out.println(e); + e.printStackTrace(); // Print the exception for debugging purposes } } } @@ -1091,10 +1162,9 @@ public class GetSchema { ### Get by skyflow IDs -- +Retrieve specific records using `skyflow_ids`. Ideal for fetching exact records when IDs are known. -An [example](https://github.com/skyflowapi/skyflow-java/blob/main/samples/src/main/java/com/example/vault/GetExample.java) -of a get call to retrieve data using Redaction type: +An [example](https://github.com/skyflowapi/skyflow-java/blob/main/samples/src/main/java/com/example/vault/GetExample.java) of a get call to retrieve data using Redaction type: ```java import com.skyflow.enums.RedactionType; @@ -1104,24 +1174,45 @@ import com.skyflow.vault.data.GetResponse; import java.util.ArrayList; +/** + * This example demonstrates how to retrieve data from the Skyflow vault using a list of Skyflow IDs. + * + * 1. Initializes the Skyflow client with a given vault ID. + * 2. Creates a request to retrieve records based on Skyflow IDs. + * 3. Specifies that the response should not return tokens. + * 4. Uses plain text redaction type for the retrieved records. + * 5. Prints the response to display the retrieved records. + */ public class GetExample { public static void main(String[] args) { try { - // Initialize Skyflow client + // Initialize Skyflow client + // Step 1: Initialize a list of Skyflow IDs (replace with actual Skyflow IDs) ArrayList ids = new ArrayList<>(); - ids.add("a581d205-1969-4350-acbe-a2a13eb871a6"); - ids.add("5ff887c3-b334-4294-9acc-70e78ae5164a"); + ids.add("a581d205-1969-4350-acbe-a2a13eb871a6"); // Replace with actual Skyflow ID + ids.add("5ff887c3-b334-4294-9acc-70e78ae5164a"); // Replace with actual Skyflow ID + + // Step 2: Create a GetRequest to retrieve records based on Skyflow IDs + // The request specifies: + // - `ids`: The list of Skyflow IDs to retrieve + // - `table`: The table from which the records will be retrieved + // - `returnTokens`: Set to false, meaning tokens will not be returned in the response + // - `redactionType`: Set to PLAIN_TEXT, meaning the retrieved records will have data redacted as plain text GetRequest getByIdRequest = GetRequest.builder() .ids(ids) - .table("table1") - .returnTokens(false) - .redactionType(RedactionType.PLAIN_TEXT) + .table("table1") // Replace with the actual table name + .returnTokens(false) // Set to false to avoid returning tokens + .redactionType(RedactionType.PLAIN_TEXT) // Redact data as plain text .build(); - GetResponse getByIdResponse = skyflowClient.vault("9f27764a10f7946fe56b3258e117").get(getByIdRequest); - System.out.println(getByIdResponse); + + // Step 3: Send the request to the Skyflow vault and retrieve the records + GetResponse getByIdResponse = skyflowClient.vault("9f27764a10f7946fe56b3258e117").get(getByIdRequest); // Replace with actual Vault ID + System.out.println(getByIdResponse); // Print the response to the console + } catch (SkyflowException e) { + // Step 4: Handle any errors that occur during the data retrieval process System.out.println("Error occurred: "); - System.out.println(e); + e.printStackTrace(); // Print the exception for debugging purposes } } } @@ -1129,27 +1220,31 @@ public class GetExample { Sample response: -```js +```json { - "data": [{ - "card_number": "4555555555555553", - "email": "john.doe@gmail.com", - "name": "john doe", - "skyflow_id": "a581d205-1969-4350-acbe-a2a13eb871a6", - }, { - "card_number": "4555555555555559", - "email": "jane.doe@gmail.com", - "name": "jane doe", - "skyflow_id": "5ff887c3-b334-4294-9acc-70e78ae5164a", - }], - "errors": [] + "data": [ + { + "card_number": "4555555555555553", + "email": "john.doe@gmail.com", + "name": "john doe", + "skyflow_id": "a581d205-1969-4350-acbe-a2a13eb871a6" + }, + { + "card_number": "4555555555555559", + "email": "jane.doe@gmail.com", + "name": "jane doe", + "skyflow_id": "5ff887c3-b334-4294-9acc-70e78ae5164a" + } + ], + "errors": [] } ``` -- +### Get tokens + +Return tokens for records. Ideal for securely processing sensitive data while maintaining data privacy. -An [example](https://github.com/skyflowapi/skyflow-java/blob/main/samples/src/main/java/com/example/vault/getExample.java) -of get call to retrieve tokens using Skyflow IDs: +An [example](https://github.com/skyflowapi/skyflow-java/blob/main/samples/src/main/java/com/example/vault/getExample.java) of get call to retrieve tokens using Skyflow IDs: ```java import com.skyflow.enums.RedactionType; @@ -1159,23 +1254,41 @@ import com.skyflow.vault.data.GetResponse; import java.util.ArrayList; +/** + * This example demonstrates how to retrieve data from the Skyflow vault and return tokens along with the records. + * + * 1. Initializes the Skyflow client with a given vault ID. + * 2. Creates a request to retrieve records based on Skyflow IDs and ensures tokens are returned. + * 3. Prints the response to display the retrieved records along with the tokens. + */ public class GetExample { public static void main(String[] args) { try { - // Initialize Skyflow client + // Initialize Skyflow client + // Step 1: Initialize a list of Skyflow IDs (replace with actual Skyflow IDs) ArrayList ids = new ArrayList<>(); - ids.add("a581d205-1969-4350-acbe-a2a13eb871a6"); - ids.add("5ff887c3-b334-4294-9acc-70e78ae5164a"); + ids.add("a581d205-1969-4350-acbe-a2a13eb871a6"); // Replace with actual Skyflow ID + ids.add("5ff887c3-b334-4294-9acc-70e78ae5164a"); // Replace with actual Skyflow ID + + // Step 2: Create a GetRequest to retrieve records based on Skyflow IDs + // The request specifies: + // - `ids`: The list of Skyflow IDs to retrieve + // - `table`: The table from which the records will be retrieved + // - `returnTokens`: Set to true, meaning tokens will be included in the response GetRequest getTokensRequest = GetRequest.builder() .ids(ids) - .table("table1") - .returnTokens(true) + .table("table1") // Replace with the actual table name + .returnTokens(true) // Set to true to include tokens in the response .build(); - GetResponse getTokensResponse = skyflowClient.vault("9f27764a10f7946fe56b3258e117").get(getTokensRequest); - System.out.println(getTokensResponse); + + // Step 3: Send the request to the Skyflow vault and retrieve the records with tokens + GetResponse getTokensResponse = skyflowClient.vault("9f27764a10f7946fe56b3258e117").get(getTokensRequest); // Replace with actual Vault ID + System.out.println(getTokensResponse); // Print the response to the console + } catch (SkyflowException e) { + // Step 4: Handle any errors that occur during the data retrieval process System.out.println("Error occurred: "); - System.out.println(e); + e.printStackTrace(); // Print the exception for debugging purposes } } } @@ -1183,29 +1296,31 @@ public class GetExample { Sample response: -```js +```json { - "data": [{ - "card_number": "3998-2139-0328-0697", - "email": "c9a6c9555060@82c092e7.bd52", - "name": "82c092e7-74c0-4e60-bd52-c9a6c9555060", - "skyflow_id": "a581d205-1969-4350-acbe-a2a13eb871a6", - }, { - "card_number": "3562-0140-8820-7499", - "email": "6174366e2bc6@59f82e89.93fc", - "name": "59f82e89-138e-4f9b-93fc-6174366e2bc6", - "skyflow_id": "5ff887c3-b334-4294-9acc-70e78ae5164a", - }], - "errors": [] + "data": [ + { + "card_number": "3998-2139-0328-0697", + "email": "c9a6c9555060@82c092e7.bd52", + "name": "82c092e7-74c0-4e60-bd52-c9a6c9555060", + "skyflow_id": "a581d205-1969-4350-acbe-a2a13eb871a6" + }, + { + "card_number": "3562-0140-8820-7499", + "email": "6174366e2bc6@59f82e89.93fc", + "name": "59f82e89-138e-4f9b-93fc-6174366e2bc6", + "skyflow_id": "5ff887c3-b334-4294-9acc-70e78ae5164a" + } + ], + "errors": [] } ``` ### Get By column name and column values -- +Retrieve records by unique column values. Ideal for querying data without knowing Skyflow IDs, using alternate unique identifiers. -An [example](https://github.com/skyflowapi/skyflow-java/blob/main/samples/src/main/java/com/example/vault/GetExample.java) -of get call to retrieve data using column name and column values +An [example](https://github.com/skyflowapi/skyflow-java/blob/main/samples/src/main/java/com/example/vault/GetExample.java) of get call to retrieve data using column name and column values: ```java import com.skyflow.enums.RedactionType; @@ -1215,24 +1330,43 @@ import com.skyflow.vault.data.GetResponse; import java.util.ArrayList; +/** + * This example demonstrates how to retrieve data from the Skyflow vault based on column values. + * + * 1. Initializes the Skyflow client with a given vault ID. + * 2. Creates a request to retrieve records based on specific column values (e.g., email addresses). + * 3. Prints the response to display the retrieved records after redacting sensitive data based on the specified redaction type. + */ public class GetExample { public static void main(String[] args) { try { - // Initialize Skyflow client + // Initialize Skyflow client + // Step 1: Initialize a list of column values (email addresses in this case) ArrayList columnValues = new ArrayList<>(); - columnValues.add("john.doe@gmail.com"); - columnValues.add("jane.doe@gmail.com"); + columnValues.add("john.doe@gmail.com"); // Example email address + columnValues.add("jane.doe@gmail.com"); // Example email address + + // Step 2: Create a GetRequest to retrieve records based on column values + // The request specifies: + // - `table`: The table from which the records will be retrieved + // - `columnName`: The column to filter the records by (e.g., "email") + // - `columnValues`: The list of values to match in the specified column + // - `redactionType`: Defines how sensitive data should be redacted (set to PLAIN_TEXT here) GetRequest getByColumnRequest = GetRequest.builder() - .table("table1") - .columnName("email") - .columnValues(columnValues) - .redactionType(RedactionType.PLAIN_TEXT) + .table("table1") // Replace with the actual table name + .columnName("email") // The column name to filter by (e.g., "email") + .columnValues(columnValues) // The list of column values to match + .redactionType(RedactionType.PLAIN_TEXT) // Set the redaction type (e.g., PLAIN_TEXT) .build(); - GetResponse getByColumnResponse = skyflowClient.vault("9f27764a10f7946fe56b3258e117").get(getByColumnRequest); - System.out.println(getByColumnResponse); + + // Step 3: Send the request to the Skyflow vault and retrieve the records + GetResponse getByColumnResponse = skyflowClient.vault("9f27764a10f7946fe56b3258e117").get(getByColumnRequest); // Replace with actual Vault ID + System.out.println(getByColumnResponse); // Print the response to the console + } catch (SkyflowException e) { + // Step 4: Handle any errors that occur during the data retrieval process System.out.println("Error occurred: "); - System.out.println(e); + e.printStackTrace(); // Print the exception for debugging purposes } } } @@ -1240,31 +1374,42 @@ public class GetExample { Sample response: -```js +```json { - "data": [{ - "card_number": "4555555555555553", - "email": "john.doe@gmail.com", - "name": "john doe", - "skyflow_id": "a581d205-1969-4350-acbe-a2a13eb871a6", - }, { - "card_number": "4555555555555559", - "email": "jane.doe@gmail.com", - "name": "jane doe", - "skyflow_id": "5ff887c3-b334-4294-9acc-70e78ae5164a", - }], - "errors": [] + "data": [ + { + "card_number": "4555555555555553", + "email": "john.doe@gmail.com", + "name": "john doe", + "skyflow_id": "a581d205-1969-4350-acbe-a2a13eb871a6" + }, + { + "card_number": "4555555555555559", + "email": "jane.doe@gmail.com", + "name": "jane doe", + "skyflow_id": "5ff887c3-b334-4294-9acc-70e78ae5164a" + } + ], + "errors": [] } ``` ### Redaction types -There are four accepted values for RedactionType: +Redaction types determine how sensitive data is displayed when retrieved from the vault. + +#### **Available Redaction Types** -* `PLAIN_TEXT` -* `MASKED` -* `REDACTED` -* `DEFAULT` +- `DEFAULT`: Applies the vault-configured default redaction setting. +- `REDACTED`: Completely removes sensitive data from view. +- `MASKED`: Partially obscures sensitive information. +- `PLAIN_TEXT`: Displays the full, unmasked data. + +#### **Choosing the Right Redaction Type** + +- Use `REDACTED` for scenarios requiring maximum data protection to prevent exposure of sensitive information. +- Use `MASKED` to provide partial visibility of sensitive data for less critical use cases. +- Use `PLAIN_TEXT` for internal, authorized access where full data visibility is necessary. ## Update @@ -1273,7 +1418,7 @@ where you specify parameters such as the table name, data (as a map of key value tokenStrict. If `returnTokens` is set to `true`, Skyflow returns tokens for the updated records. If `returnTokens` is set to `false`, Skyflow returns IDs for the updated records. -Update Schema: +### Construct an update request ```java import com.skyflow.enums.TokenMode; @@ -1283,37 +1428,50 @@ import com.skyflow.vault.data.UpdateResponse; import java.util.HashMap; +/** + * This example demonstrates how to update records in the Skyflow vault by providing new data and/or tokenized values, along with corresponding UpdateRequest schema. + * + */ public class UpdateSchema { public static void main(String[] args) { try { - // Initialize Skyflow client + // Initialize Skyflow client + // Step 1: Prepare the data to update in the vault + // Use a HashMap to store the data that will be updated in the specified table HashMap data = new HashMap<>(); - data.put("skyflow_id", ""); - data.put("", ""); - data.put("", ""); + data.put("skyflow_id", ""); // Skyflow ID for identifying the record to update + data.put("", ""); // Example of a column name and its value to update + data.put("", ""); // Another example of a column name and its value to update + // Step 2: Prepare the tokens (if necessary) for certain columns that require tokenization + // Use a HashMap to specify columns that need tokens in the update request HashMap tokens = new HashMap<>(); - tokens.put("", ""); + tokens.put("", ""); // Example of a column name that should be tokenized + // Step 3: Create an UpdateRequest to specify the update operation + // The request includes the table name, token mode, data, tokens, and the returnTokens flag UpdateRequest updateRequest = UpdateRequest.builder() - .table("") - .tokenMode(TokenMode.ENABLE) - .data(data) - .tokens(tokens) - .returnTokens(true) + .table("") // Replace with the actual table name to update + .tokenMode(TokenMode.ENABLE) // Specifies the tokenization mode (ENABLE means tokenization is applied) + .data(data) // The data to update in the record + .tokens(tokens) // The tokens associated with specific columns + .returnTokens(true) // Specify whether to return tokens in the response .build(); - UpdateResponse updateResponse = skyflowClient.vault("").update(updateRequest); - System.out.println(updateResponse); + + // Step 4: Send the request to the Skyflow vault and update the record + UpdateResponse updateResponse = skyflowClient.vault("").update(updateRequest); // Replace with actual Vault ID + System.out.println(updateResponse); // Print the response to confirm the update result + } catch (SkyflowException e) { + // Step 5: Handle any errors that occur during the update operation System.out.println("Error occurred: "); - System.out.println(e); + e.printStackTrace(); // Print the exception for debugging purposes } } } ``` -An [example](https://github.com/skyflowapi/skyflow-java/blob/main/samples/src/main/java/com/example/vault/UpdateExample.java) -of update call: +### An [example](https://github.com/skyflowapi/skyflow-java/blob/main/samples/src/main/java/com/example/vault/UpdateExample.java) of update call ```java import com.skyflow.enums.TokenMode; @@ -1323,29 +1481,47 @@ import com.skyflow.vault.data.UpdateResponse; import java.util.HashMap; +/** + * This example demonstrates how to update a record in the Skyflow vault with specified data and tokens. + * + * 1. Initializes the Skyflow client with a given vault ID. + * 2. Constructs an update request with data to modify and tokens to include. + * 3. Sends the request to update the record in the vault. + * 4. Prints the response to confirm the success or failure of the update operation. + */ public class UpdateExample { public static void main(String[] args) { try { - // Initialize Skyflow client + // Initialize Skyflow client + // Step 1: Prepare the data to update in the vault + // A HashMap is used to store the data that will be updated in the specified table HashMap data = new HashMap<>(); - data.put("skyflow_id", "5b699e2c-4301-4f9f-bcff-0a8fd3057413"); - data.put("name", "john doe"); - data.put("card_number", "4111111111111115"); + data.put("skyflow_id", "5b699e2c-4301-4f9f-bcff-0a8fd3057413"); // Skyflow ID identifies the record to update + data.put("name", "john doe"); // Updating the "name" column with a new value + data.put("card_number", "4111111111111115"); // Updating the "card_number" column with a new value + // Step 2: Prepare the tokens to include in the update request + // Tokens can be included to update sensitive data with tokenized values HashMap tokens = new HashMap<>(); - tokens.put("name", "72b8ffe3-c8d3-4b4f-8052-38b2a7405b5a"); + tokens.put("name", "72b8ffe3-c8d3-4b4f-8052-38b2a7405b5a"); // Tokenized value for the "name" column + // Step 3: Create an UpdateRequest to define the update operation + // The request specifies the table name, token mode, data, and tokens for the update UpdateRequest updateRequest = UpdateRequest.builder() - .table("table1") - .tokenMode(TokenMode.ENABLE) - .data(data) - .tokens(tokens) + .table("table1") // Replace with the actual table name to update + .tokenMode(TokenMode.ENABLE) // Token mode enabled to allow tokenization of sensitive data + .data(data) // The data to update in the record + .tokens(tokens) // The tokenized values for sensitive columns .build(); - UpdateResponse updateResponse = skyflowClient.vault("9f27764a10f7946fe56b3258e117").update(updateRequest); - System.out.println(updateResponse); + + // Step 4: Send the update request to the Skyflow vault + UpdateResponse updateResponse = skyflowClient.vault("9f27764a10f7946fe56b3258e117").update(updateRequest); // Replace with your actual Vault ID + System.out.println(updateResponse); // Print the response to confirm the update result + } catch (SkyflowException e) { + // Step 5: Handle any exceptions that occur during the update operation System.out.println("Error occurred: "); - System.out.println(e); + e.printStackTrace(); // Print the exception stack trace for debugging purposes } } } @@ -1353,9 +1529,9 @@ public class UpdateExample { Sample response: -- `returnTokens` set to `true` +- When `returnTokens` is set to `true` -```js +```json { "skyflowId": "5b699e2c-4301-4f9f-bcff-0a8fd3057413", "name": "72b8ffe3-c8d3-4b4f-8052-38b2a7405b5a", @@ -1363,9 +1539,9 @@ Sample response: } ``` -- `returnTokens` set to `false` +- When `returnTokens` is set to `false` -```js +```json { "skyflowId": "5b699e2c-4301-4f9f-bcff-0a8fd3057413" } @@ -1376,7 +1552,7 @@ Sample response: To delete records using Skyflow IDs, use the `delete` method. The `DeleteRequest` class accepts a list of Skyflow IDs that you want to delete, as shown below: -Delete schema: +### Construct a delete request ```java import com.skyflow.errors.SkyflowException; @@ -1385,27 +1561,42 @@ import com.skyflow.vault.data.DeleteResponse; import java.util.ArrayList; +/** + * This example demonstrates how to delete records from a Skyflow vault using specified Skyflow IDs, along with corresponding DeleteRequest schema. + * + */ public class DeleteSchema { public static void main(String[] args) { try { - // Initialize Skyflow client + // Initialize Skyflow client + // Step 1: Prepare a list of Skyflow IDs for the records to delete + // The list stores the Skyflow IDs of the records that need to be deleted from the vault ArrayList ids = new ArrayList<>(); - ids.add(""); - ids.add(""); - ids.add(""); - DeleteRequest deleteRequest = DeleteRequest.builder().ids(ids).table("").build(); - DeleteResponse deleteResponse = skyflowClient.vault("").delete(deleteRequest); - System.out.println(deleteResponse); + ids.add(""); // Replace with actual Skyflow ID 1 + ids.add(""); // Replace with actual Skyflow ID 2 + ids.add(""); // Replace with actual Skyflow ID 3 + + // Step 2: Create a DeleteRequest to define the delete operation + // The request specifies the table from which to delete the records and the IDs of the records to delete + DeleteRequest deleteRequest = DeleteRequest.builder() + .ids(ids) // List of Skyflow IDs to delete + .table("") // Replace with the actual table name from which to delete + .build(); + + // Step 3: Send the delete request to the Skyflow vault + DeleteResponse deleteResponse = skyflowClient.vault("").delete(deleteRequest); // Replace with your actual Vault ID + System.out.println(deleteResponse); // Print the response to confirm the delete result + } catch (SkyflowException e) { + // Step 4: Handle any exceptions that occur during the delete operation System.out.println("Error occurred: "); - System.out.println(e); + e.printStackTrace(); // Print the exception stack trace for debugging purposes } } } ``` -An [example](https://github.com/skyflowapi/skyflow-java/blob/main/samples/src/main/java/com/example/vault/DeleteExample.java) -of delete call: +### An [example](https://github.com/skyflowapi/skyflow-java/blob/main/samples/src/main/java/com/example/vault/DeleteExample.java) of delete call: ```java import com.skyflow.errors.SkyflowException; @@ -1414,20 +1605,40 @@ import com.skyflow.vault.data.DeleteResponse; import java.util.ArrayList; +/** + * This example demonstrates how to delete records from a Skyflow vault using specified Skyflow IDs. + * + * 1. Initializes the Skyflow client with a given Vault ID. + * 2. Constructs a delete request by specifying the IDs of the records to delete. + * 3. Sends the delete request to the Skyflow vault to delete the specified records. + * 4. Prints the response to confirm the success or failure of the delete operation. + */ public class DeleteExample { public static void main(String[] args) { try { - // Initialize Skyflow client + // Initialize Skyflow client + // Step 1: Prepare a list of Skyflow IDs for the records to delete + // The list stores the Skyflow IDs of the records that need to be deleted from the vault ArrayList ids = new ArrayList<>(); - ids.add("9cbf66df-6357-48f3-b77b-0f1acbb69280"); - ids.add("ea74bef4-f27e-46fe-b6a0-a28e91b4477b"); - ids.add("47700796-6d3b-4b54-9153-3973e281cafb"); - DeleteRequest deleteRequest = DeleteRequest.builder().ids(ids).table("table1").build(); - DeleteResponse deleteResponse = skyflowClient.vault("9f27764a10f7946fe56b3258e117").delete(deleteRequest); - System.out.println(deleteResponse); + ids.add("9cbf66df-6357-48f3-b77b-0f1acbb69280"); // Replace with actual Skyflow ID 1 + ids.add("ea74bef4-f27e-46fe-b6a0-a28e91b4477b"); // Replace with actual Skyflow ID 2 + ids.add("47700796-6d3b-4b54-9153-3973e281cafb"); // Replace with actual Skyflow ID 3 + + // Step 2: Create a DeleteRequest to define the delete operation + // The request specifies the table from which to delete the records and the IDs of the records to delete + DeleteRequest deleteRequest = DeleteRequest.builder() + .ids(ids) // List of Skyflow IDs to delete + .table("table1") // Replace with the actual table name from which to delete + .build(); + + // Step 3: Send the delete request to the Skyflow vault + DeleteResponse deleteResponse = skyflowClient.vault("9f27764a10f7946fe56b3258e117").delete(deleteRequest); // Replace with your actual Vault ID + System.out.println(deleteResponse); // Print the response to confirm the delete result + } catch (SkyflowException e) { + // Step 4: Handle any exceptions that occur during the delete operation System.out.println("Error occurred: "); - System.out.println(e); + e.printStackTrace(); // Print the exception stack trace for debugging purposes } } } @@ -1445,57 +1656,85 @@ Sample response: } ``` -### Query +## Query -To retrieve data with SQL queries, use the `query` method. The `QueryRequest` class accepts a `query` parameter as -follows: +To retrieve data with SQL queries, use the `query` method. The `QueryRequest` class accepts a `query` parameter, as shown below. -Query Schema +### Construct a query request + +Refer to [Query your data](https://docs.skyflow.com/query-data/) and [Execute Query](https://docs.skyflow.com/record/#QueryService_ExecuteQuery) for guidelines and restrictions on supported SQL statements, operators, and keywords. ```java import com.skyflow.errors.SkyflowException; import com.skyflow.vault.data.QueryRequest; import com.skyflow.vault.data.QueryResponse; -public class QueryExample { +/** + * This example demonstrates how to execute a custom SQL query on a Skyflow vault, along with QueryRequest schema. + * + */ +public class QuerySchema { public static void main(String[] args) { try { - // initialize Skyflow client - String query = ""; - QueryRequest queryRequest = QueryRequest.builder().query(query).build(); - QueryResponse queryResponse = skyflowClient.vault("").query(queryRequest); - System.out.println(queryResponse); + // Initialize Skyflow client + // Step 1: Define the SQL query to execute on the Skyflow vault + // Replace "" with the actual SQL query you want to run + String query = ""; // Example: "SELECT * FROM table1 WHERE column1 = 'value'" + + // Step 2: Create a QueryRequest with the specified SQL query + QueryRequest queryRequest = QueryRequest.builder() + .query(query) // SQL query to execute + .build(); + + // Step 3: Execute the query request on the specified Skyflow vault + QueryResponse queryResponse = skyflowClient.vault("").query(queryRequest); // Replace with your actual Vault ID + System.out.println(queryResponse); // Print the response containing the query results + } catch (SkyflowException e) { + // Step 4: Handle any exceptions that occur during the query execution System.out.println("Error occurred: "); - System.out.println(e); + e.printStackTrace(); // Print the exception stack trace for debugging } } } ``` -See [Query your data](https://docs.skyflow.com/query-data/) -and [Execute Query](https://docs.skyflow.com/record/#QueryService_ExecuteQuery) for guidelines and restrictions on -supported SQL statements, operators, and keywords. - -An [example](https://github.com/skyflowapi/skyflow-java/blob/main/samples/src/main/java/com/example/vault/QueryExample.java) -of query call: +### An [example](https://github.com/skyflowapi/skyflow-java/blob/main/samples/src/main/java/com/example/vault/QueryExample.java) of query call ```java import com.skyflow.errors.SkyflowException; import com.skyflow.vault.data.QueryRequest; import com.skyflow.vault.data.QueryResponse; +/** + * This example demonstrates how to execute a SQL query on a Skyflow vault to retrieve data. + * + * 1. Initializes the Skyflow client with the Vault ID. + * 2. Constructs a query request with a specified SQL query. + * 3. Executes the query against the Skyflow vault. + * 4. Prints the response from the query execution. + */ public class QueryExample { public static void main(String[] args) { try { - // initialize Skyflow client + // Initialize Skyflow client + // Step 1: Define the SQL query + // Example query: Retrieve all records from the "cards" table with a specific skyflow_id String query = "SELECT * FROM cards WHERE skyflow_id='3ea3861-x107-40w8-la98-106sp08ea83f'"; - QueryRequest queryRequest = QueryRequest.builder().query(query).build(); - QueryResponse queryResponse = skyflowClient.vault("9f27764a10f7946fe56b3258e117").query(queryRequest); - System.out.println(queryResponse); + + // Step 2: Create a QueryRequest with the SQL query + QueryRequest queryRequest = QueryRequest.builder() + .query(query) // SQL query to execute + .build(); + + // Step 3: Execute the query request on the specified Skyflow vault + QueryResponse queryResponse = skyflowClient.vault("9f27764a10f7946fe56b3258e117").query(queryRequest); // Vault ID: 9f27764a10f7946fe56b3258e117 + System.out.println(queryResponse); // Print the query response (contains query results) + } catch (SkyflowException e) { + // Step 4: Handle any exceptions that occur during the query execution System.out.println("Error occurred: "); - System.out.println(e); + e.printStackTrace(); // Print the exception stack trace for debugging } } } @@ -1503,28 +1742,31 @@ public class QueryExample { Sample response: -```js +```json { - "fields": [{ - "card_number": "XXXXXXXXXXXX1112", - "name": "S***ar", - "skyflow_id": "3ea3861-x107-40w8-la98-106sp08ea83f", - "tokenizedData": null - }] + "fields": [ + { + "card_number": "XXXXXXXXXXXX1112", + "name": "S***ar", + "skyflow_id": "3ea3861-x107-40w8-la98-106sp08ea83f", + "tokenizedData": null + } + ] } ``` # Connections -The [connections](https://github.com/skyflowapi/skyflow-java/tree/main/src/main/java/com/skyflow/vault/connection) -module is used to invoke INBOUND and/or OUTBOUND connections. +Skyflow Connections is a gateway service that uses tokenization to securely send and receive data between your systems and first- or third-party services. The [connections](https://github.com/skyflowapi/skyflow-java/tree/main/src/main/java/com/skyflow/vault/connection) module invokes both inbound and/or outbound connections. -## Invoke Connection +- **Inbound connections**: Act as intermediaries between your client and server, tokenizing sensitive data before it reaches your backend, ensuring downstream services handle only tokenized data. +- **Outbound connections**: Enable secure extraction of data from the vault and transfer it to third-party services via your backend server, such as processing checkout or card issuance flows. -Using Skyflow Connection, end-user applications can integrate checkout/card issuance flow with their apps/systems. To -invoke connection, use the `invoke` method of the Skyflow client. +## Invoke a connection -Invoke Connection Schema: +To invoke a connection, use the `invoke` method of the Skyflow client. + +### Construct an invoke connection request ```java import com.skyflow.enums.RequestMethod; @@ -1535,44 +1777,65 @@ import com.skyflow.vault.connection.InvokeConnectionResponse; import java.util.HashMap; import java.util.Map; +/** + * This example demonstrates how to invoke an external connection using the Skyflow SDK, along with corresponding InvokeConnectionRequest schema. + * + */ public class InvokeConnectionSchema { public static void main(String[] args) { try { - // Initialize Skyflow client + // Initialize Skyflow client + // Step 1: Define the request body parameters + // These are the values you want to send in the request body Map requestBody = new HashMap<>(); requestBody.put("", ""); requestBody.put("", ""); + // Step 2: Define the request headers + // Add any required headers that need to be sent with the request Map requestHeaders = new HashMap<>(); requestHeaders.put("", ""); requestHeaders.put("", ""); + // Step 3: Define the path parameters + // Path parameters are part of the URL and typically used in RESTful APIs Map pathParams = new HashMap<>(); pathParams.put("", ""); pathParams.put("", ""); + // Step 4: Define the query parameters + // Query parameters are included in the URL after a '?' and are used to filter or modify the response Map queryParams = new HashMap<>(); queryParams.put("", ""); queryParams.put("", ""); + // Step 5: Build the InvokeConnectionRequest using the provided parameters InvokeConnectionRequest invokeConnectionRequest = InvokeConnectionRequest.builder() - .method(RequestMethod.POST) - .requestBody(requestBody) - .requestHeaders(requestHeaders) - .pathParams(pathParams) - .queryParams(queryParams) + .method(RequestMethod.POST) // The HTTP method to use for the request (POST in this case) + .requestBody(requestBody) // The body of the request + .requestHeaders(requestHeaders) // The headers to include in the request + .pathParams(pathParams) // The path parameters for the URL + .queryParams(queryParams) // The query parameters to append to the URL .build(); + + // Step 6: Invoke the connection using the request + // Replace "" with the actual connection ID you are using InvokeConnectionResponse invokeConnectionResponse = skyflowClient.connection("").invoke(invokeConnectionRequest); + + // Step 7: Print the response from the invoked connection + // This response contains the result of the request sent to the external system System.out.println(invokeConnectionResponse); + } catch (SkyflowException e) { + // Step 8: Handle any exceptions that occur during the connection invocation System.out.println("Error occurred: "); - System.out.println(e); + e.printStackTrace(); // Print the exception stack trace for debugging } } } ``` -`methodName` supports the following methods: +`method` supports the following methods: - GET - POST @@ -1580,11 +1843,9 @@ public class InvokeConnectionSchema { - PATCH - DELETE -**pathParams, queryParams, requestHeader, requestBody** are the JSON objects represented as HashMaps, that will be sent -through the connection integration url. +**pathParams, queryParams, requestHeader, requestBody** are the JSON objects represented as HashMaps, that will be sent through the connection integration url. -An [example](https://github.com/skyflowapi/skyflow-java/blob/main/samples/src/main/java/com/example/connection/InvokeConnectionExample.java) -of invokeConnection: +### An [example](https://github.com/skyflowapi/skyflow-java/blob/main/samples/src/main/java/com/example/connection/InvokeConnectionExample.java) of invokeConnection ```java import com.skyflow.Skyflow; @@ -1599,39 +1860,65 @@ import com.skyflow.vault.connection.InvokeConnectionResponse; import java.util.HashMap; import java.util.Map; +/** + * This example demonstrates how to invoke an external connection using the Skyflow SDK. + * It configures a connection, sets up the request, and sends a POST request to the external service. + * + * 1. Initialize Skyflow client with connection details. + * 2. Define the request body, headers, and method. + * 3. Execute the connection request. + * 4. Print the response from the invoked connection. + */ public class InvokeConnectionExample { public static void main(String[] args) { try { + // Initialize Skyflow client + // Step 1: Set up credentials and connection configuration + // Load credentials from a JSON file (you need to provide the correct path) Credentials credentials = new Credentials(); credentials.setPath("/path/to/credentials.json"); + // Define the connection configuration (URL and credentials) ConnectionConfig connectionConfig = new ConnectionConfig(); - connectionConfig.setConnectionId(""); - connectionConfig.setConnectionUrl("https://connection.url.com"); - connectionConfig.setCredentials(credentials); + connectionConfig.setConnectionId(""); // Replace with actual connection ID + connectionConfig.setConnectionUrl("https://connection.url.com"); // Replace with actual connection URL + connectionConfig.setCredentials(credentials); // Set credentials for the connection + // Initialize the Skyflow client with the connection configuration Skyflow skyflowClient = Skyflow.builder() - .setLogLevel(LogLevel.DEBUG) - .addConnectionConfig(connectionConfig) - .build(); + .setLogLevel(LogLevel.DEBUG) // Set log level to DEBUG for detailed logs + .addConnectionConfig(connectionConfig) // Add connection configuration to client + .build(); // Build the Skyflow client instance + // Step 2: Define the request body and headers + // Map for request body parameters Map requestBody = new HashMap<>(); - requestBody.put("card_number", "4337-1696-5866-0865"); - requestBody.put("ssn", "524-41-4248"); + requestBody.put("card_number", "4337-1696-5866-0865"); // Example card number + requestBody.put("ssn", "524-41-4248"); // Example SSN + // Map for request headers Map requestHeaders = new HashMap<>(); - requestHeaders.put("Content-Type", "application/json"); + requestHeaders.put("Content-Type", "application/json"); // Set content type for the request + // Step 3: Build the InvokeConnectionRequest with required parameters + // Set HTTP method to POST, include the request body and headers InvokeConnectionRequest invokeConnectionRequest = InvokeConnectionRequest.builder() - .method(RequestMethod.POST) - .requestBody(requestBody) - .requestHeaders(requestHeaders) - .build(); + .method(RequestMethod.POST) // HTTP POST method + .requestBody(requestBody) // Add request body parameters + .requestHeaders(requestHeaders) // Add headers + .build(); // Build the request + + // Step 4: Invoke the connection and capture the response + // Replace "" with the actual connection ID InvokeConnectionResponse invokeConnectionResponse = skyflowClient.connection("").invoke(invokeConnectionRequest); - System.out.println(invokeConnectionResponse); + + // Step 5: Print the response from the connection invocation + System.out.println(invokeConnectionResponse); // Print the response to the console + } catch (SkyflowException e) { + // Step 6: Handle any exceptions that occur during the connection invocation System.out.println("Error occurred: "); - System.out.println(e); + e.printStackTrace(); // Print the exception stack trace for debugging } } } @@ -1639,85 +1926,383 @@ public class InvokeConnectionExample { Sample response: -```js -InvokeConnectionResponse{ - response={ - "card_number":"4337-1696-5866-0865", - "ssn":"524-41-4248" +```json +{ + "data": { + "card_number": "4337-1696-5866-0865", + "ssn": "524-41-4248" + }, + "metadata": { + "requestId": "4a3453b5-7aa4-4373-98d7-cf102b1f6f97" + } } ``` -## Logging +# Authenticate with bearer tokens + +This section covers methods for generating and managing tokens to authenticate API calls: + +- **Generate a bearer token**: + Enable the creation of bearer tokens using service account credentials. These tokens, valid for 60 minutes, provide secure access to Vault services and management APIs based on the service account's permissions. Use this for general API calls when you only need basic authentication without additional context or role-based restrictions. +- **Generate a bearer token with context**: + Support embedding context values into bearer tokens, enabling dynamic access control and the ability to track end-user identity. These tokens include context claims and allow flexible authorization for Vault services. Use this when policies depend on specific contextual attributes or when tracking end-user identity is required. +- **Generate a scoped bearer token**: + Facilitate the creation of bearer tokens with role-specific access, ensuring permissions are limited to the operations allowed by the designated role. This is particularly useful for service accounts with multiple roles. Use this to enforce fine-grained role-based access control, ensuring tokens only grant permissions for a specific role. +- **Generate signed data tokens**: + Add an extra layer of security by digitally signing data tokens with the service account's private key. These signed tokens can be securely detokenized, provided the necessary bearer token and permissions are available. Use this to add cryptographic protection to sensitive data, enabling secure detokenization with verified integrity and authenticity. + +## Generate a bearer token -The skyflow java SDK provides useful logging using python's inbuilt `logging` library. By default, the logging level of -the SDK is set to `LogLevel.ERROR`. This can be changed by using `setLogLevel(logLevel)` method as shown below: +The [Service Account](https://github.com/skyflowapi/skyflow-java/tree/v2/src/main/java/com/skyflow/serviceaccount/util) Java module generates service account tokens using a service account credentials file, which is provided when a service account is created. The tokens generated by this module are valid for 60 minutes and can be used to make API calls to the [Data](https://docs.skyflow.com/record/) and [Management](https://docs.skyflow.com/management/) APIs, depending on the permissions assigned to the service account. + +The `BearerToken` utility class generates bearer tokens using a credentials JSON file. Alternatively, you can pass the credentials as a string. + +[Example](https://github.com/skyflowapi/skyflow-java/blob/main/samples/src/main/java/com/example/serviceaccount/BearerTokenGenerationExample.java): + +```java +/** + * Example program to generate a Bearer Token using Skyflow's BearerToken utility. + * The token can be generated in two ways: + * 1. Using the file path to a credentials.json file. + * 2. Using the JSON content of the credentials file as a string. + */ +public class BearerTokenGenerationExample { + public static void main(String[] args) { + // Variable to store the generated token + String token = null; + + // Example 1: Generate Bearer Token using a credentials.json file + try { + // Specify the full file path to the credentials.json file + String filePath = ""; + + // Check if the token is either not initialized or has expired + if (Token.isExpired(token)) { + // Create a BearerToken object using the credentials file + BearerToken bearerToken = BearerToken.builder() + .setCredentials(new File(filePath)) // Set credentials from the file path + .build(); + + // Generate a new Bearer Token + token = bearerToken.getBearerToken(); + } + + // Print the generated Bearer Token to the console + System.out.println("Generated Bearer Token (from file): " + token); + } catch (SkyflowException e) { + // Handle any exceptions encountered during the token generation process + e.printStackTrace(); + } + + // Example 2: Generate Bearer Token using the credentials JSON as a string + try { + // Provide the credentials JSON content as a string + String fileContents = ""; + + // Check if the token is either not initialized or has expired + if (Token.isExpired(token)) { + // Create a BearerToken object using the credentials string + BearerToken bearerToken = BearerToken.builder() + .setCredentials(fileContents) // Set credentials from the string + .build(); + + // Generate a new Bearer Token + token = bearerToken.getBearerToken(); + } + + // Print the generated Bearer Token to the console + System.out.println("Generated Bearer Token (from string): " + token); + } catch (SkyflowException e) { + // Handle any exceptions encountered during the token generation process + e.printStackTrace(); + } + } +} +``` + +## Generate bearer tokens with context + +**Context-aware authorization** embeds context values into a bearer token during its generation and so you can reference those values in your policies. This enables more flexible access controls, such as helping you track end-user identity when making API calls using service accounts, and facilitates using signed data tokens during detokenization. . + +A service account with the `context_id` identifier generates bearer tokens containing context information, represented as a JWT claim in a Skyflow-generated bearer token. Tokens generated from such service accounts include a `context_identifier` claim, are valid for 60 minutes, and can be used to make API calls to the Data and Management APIs, depending on the service account's permissions. + +[Example](https://github.com/skyflowapi/skyflow-java/blob/main/samples/src/main/java/com/example/serviceaccount/BearerTokenGenerationWithContextExample.java): ```java -import com.skyflow.Skyflow; -import com.skyflow.config.Credentials; -import com.skyflow.config.VaultConfig; -import com.skyflow.enums.Env; -import com.skyflow.enums.LogLevel; import com.skyflow.errors.SkyflowException; +import com.skyflow.serviceaccount.util.BearerToken; -public class ChangeLogLevel { - public static void main(String[] args) throws SkyflowException { - // Pass only one of apiKey, token, credentialsString or path in credentials - Credentials credentials = new Credentials(); - credentials.setToken(""); +import java.io.File; - VaultConfig config = new VaultConfig(); - config.setVaultId(""); // Primary vault - config.setClusterId(""); // ID from your vault URL Eg https://{clusterId}.vault.skyflowapis.com - config.setEnv(Env.PROD); // Env by default is set to PROD - config.setCredentials(credentials); // Individual credentials +/** + * Example program to generate a Bearer Token using Skyflow's BearerToken utility. + * The token is generated using two approaches: + * 1. By providing the credentials.json file path. + * 2. By providing the contents of credentials.json as a string. + */ +public class BearerTokenGenerationWithContextExample { + public static void main(String[] args) { + // Variable to store the generated Bearer Token + String bearerToken = null; - JsonObject credentialsObject = new JsonObject(); - credentialsObject.addProperty("clientID", ""); - credentialsObject.addProperty("clientName", ""); - credentialsObject.addProperty("TokenURI", ""); - credentialsObject.addProperty("keyID", ""); - credentialsObject.addProperty("privateKey", ""); + // Approach 1: Generate Bearer Token by specifying the path to the credentials.json file + try { + // Replace with the full path to your credentials.json file + String filePath = ""; - // To generate Bearer Token from credentials string. - Credentials skyflowCredentials = new Credentials(); - skyflowCredentials.setCredentialsString(credentialsObject.toString()); + // Create a BearerToken object using the file path + BearerToken token = BearerToken.builder() + .setCredentials(new File(filePath)) // Set credentials using a File object + .setCtx("abc") // Set context string (example: "abc") + .build(); // Build the BearerToken object - Skyflow skyflowClient = Skyflow.builder() - .addVaultConfig(config) // Add vault config - .addSkyflowCredentials(skyflowCredentials) // Skyflow credentials will be used if no individual credentials are passed - .setLogLevel(LogLevel.INFO) // Set log level. By default, it is set to ERROR - .build(); + // Retrieve the Bearer Token as a string + bearerToken = token.getBearerToken(); + + // Print the generated Bearer Token to the console + System.out.println(bearerToken); + } catch (SkyflowException e) { + // Handle exceptions specific to Skyflow operations + e.printStackTrace(); + } + + // Approach 2: Generate Bearer Token by specifying the contents of credentials.json as a string + try { + // Replace with the actual contents of your credentials.json file + String fileContents = ""; + + // Create a BearerToken object using the file contents as a string + BearerToken token = BearerToken.builder() + .setCredentials(fileContents) // Set credentials using a string representation of the file + .setCtx("abc") // Set context string (example: "abc") + .build(); // Build the BearerToken object + + // Retrieve the Bearer Token as a string + bearerToken = token.getBearerToken(); + + // Print the generated Bearer Token to the console + System.out.println(bearerToken); + } catch (SkyflowException e) { + // Handle exceptions specific to Skyflow operations + e.printStackTrace(); + } + } +} +``` + +## Generate scoped bearer tokens + +A service account with multiple roles can generate bearer tokens with access limited to a specific role by specifying the appropriate `roleID`. This can be used to limit access to specific roles for services with multiple responsibilities, such as segregating access for billing and analytics. The generated bearer tokens are valid for 60 minutes and can only execute operations permitted by the permissions associated with the designated role. + +[Example](https://github.com/skyflowapi/skyflow-java/blob/main/samples/src/main/java/com/example/serviceaccount/ScopedTokenGenerationExample.java): + +```java +import com.skyflow.errors.SkyflowException; +import com.skyflow.serviceaccount.util.BearerToken; + +import java.io.File; +import java.util.ArrayList; + +/** + * Example program to generate a Scoped Token using Skyflow's BearerToken utility. + * The token is generated by providing the file path to the credentials.json file + * and specifying roles associated with the token. + */ +public class ScopedTokenGenerationExample { + public static void main(String[] args) { + // Variable to store the generated scoped token + String scopedToken = null; + + // Example: Generate Scoped Token by specifying the credentials.json file path + try { + // Create a list of roles that the generated token will be scoped to + ArrayList roles = new ArrayList<>(); + roles.add("ROLE_ID"); // Add a specific role to the list (e.g., "ROLE_ID") + + // Specify the full file path to the service account's credentials.json file + String filePath = ""; + + // Create a BearerToken object using the credentials file and associated roles + BearerToken bearerToken = BearerToken.builder() + .setCredentials(new File(filePath)) // Set credentials using the credentials.json file + .setRoles(roles) // Set the roles that the token should be scoped to + .build(); // Build the BearerToken object + + // Retrieve the generated scoped token + scopedToken = bearerToken.getBearerToken(); + + // Print the generated scoped token to the console + System.out.println(scopedToken); + } catch (SkyflowException e) { + // Handle exceptions that may occur during token generation + e.printStackTrace(); + } } } ``` -Currently, the following 5 log levels are supported: +Notes: + +- You can pass either the file path of a service account key credentials file or the service account key credentials as a string to the `setCredentials` method of the `BearerTokenBuilder` class. +- If both a file path and a string are provided, the last method used takes precedence. +- To generate multiple bearer tokens concurrently using threads, refer to the following [example](https://github.com/skyflowapi/skyflow-java/blob/main/samples/src/main/java/com/example/serviceaccount/BearerTokenGenerationUsingThreadsExample.java). + +## Signed Data Tokens Generation + +Skyflow generates data tokens when sensitive data is inserted into the vault. These data tokens can be digitally signed +with the private key of the service account credentials, which adds an additional layer of protection. Signed tokens can +be detokenized by passing the signed data token and a bearer token generated from service account credentials. The +service account must have appropriate permissions and context to detokenize the signed data tokens. + +[Example](https://github.com/skyflowapi/skyflow-java/blob/main/samples/src/main/java/com/example/serviceaccount/SignedTokenGenerationExample.java): + +```java +import com.skyflow.errors.SkyflowException; +import com.skyflow.serviceaccount.util.SignedDataTokenResponse; +import com.skyflow.serviceaccount.util.SignedDataTokens; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +public class SignedTokenGenerationExample { + public static void main(String[] args) { + List signedTokenValues; + // Generate Signed data token with context by specifying credentials.json file path + try { + String filePath = ""; + String context = "abc"; + ArrayList dataTokens = new ArrayList<>(); + dataTokens.add("YOUR_DATA_TOKEN_1"); + SignedDataTokens signedToken = SignedDataTokens.builder() + .setCredentials(new File(filePath)) + .setCtx(context) + .setTimeToLive(30) // in seconds + .setDataTokens(dataTokens) + .build(); + signedTokenValues = signedToken.getSignedDataTokens(); + System.out.println(signedTokenValues); + } catch (SkyflowException e) { + e.printStackTrace(); + } + + // Generate Signed data token with context by specifying credentials.json as string + try { + String fileContents = ""; + String context = "abc"; + ArrayList dataTokens = new ArrayList<>(); + dataTokens.add("YOUR_DATA_TOKEN_1"); + SignedDataTokens signedToken = SignedDataTokens.builder() + .setCredentials(fileContents) + .setCtx(context) + .setTimeToLive(30) // in seconds + .setDataTokens(dataTokens) + .build(); + signedTokenValues = signedToken.getSignedDataTokens(); + System.out.println(signedTokenValues); + } catch (SkyflowException e) { + e.printStackTrace(); + } + } +} +``` -- `DEBUG`: +Response: - When `LogLevel.DEBUG` is passed, all level of logs will be printed(DEBUG, INFO, WARN, ERROR) +```json +[ + { + "dataToken": "5530-4316-0674-5748", + "signedDataToken": "signed_token_eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJzLCpZjA" + } +] +``` -- `INFO`: +Notes: - When `LogLevel.INFO` is passed, INFO logs for every event that has occurred during the SDK flow execution will be - printed along with WARN and ERROR logs +- You can provide either the file path to a service account key credentials file or the service account key credentials as a string to the `setCredentials` method of the `SignedDataTokensBuilder` class. +- If both a file path and a string are passed to the `setCredentials` method, the most recently specified input takes precedence. +- The `time-to-live` (TTL) value should be specified in seconds. +- By default, the TTL value is set to 60 seconds. -- `WARN`: +# Logging - When `LogLevel.WARN` is passed, WARN and ERROR logs will be printed +The SDK provides logging with Java's built-in logging library. By default, the SDK's logging level is set to `LogLevel.ERROR`. This can be changed using the `setLogLevel(logLevel)` method, as shown below: -- `ERROR`: +Currently, the following five log levels are supported: +- `DEBUG`**:** + When `LogLevel.DEBUG` is passed, logs at all levels will be printed (DEBUG, INFO, WARN, ERROR). +- `INFO`**:** + When `LogLevel.INFO` is passed, INFO logs for every event that occurs during SDK flow execution will be printed, along with WARN and ERROR logs. +- `WARN`**:** + When `LogLevel.WARN` is passed, only WARN and ERROR logs will be printed. +- `ERROR`**:** When `LogLevel.ERROR` is passed, only ERROR logs will be printed. +- `OFF`**:** + `LogLevel.OFF` can be used to turn off all logging from the Skyflow Java SDK. + +**Note:** The ranking of logging levels is as follows: `DEBUG` \< `INFO` \< `WARN` \< `ERROR` \< `OFF`. + +```java +import com.skyflow.Skyflow; +import com.skyflow.config.Credentials; +import com.skyflow.config.VaultConfig; +import com.skyflow.enums.Env; +import com.skyflow.enums.LogLevel; +import com.skyflow.errors.SkyflowException; + +/** + * This example demonstrates how to configure the Skyflow client with custom log levels + * and authentication credentials (either token, credentials string, or other methods). + * It also shows how to configure a vault connection using specific parameters. + * + * 1. Set up credentials with a Bearer token or credentials string. + * 2. Define the Vault configuration. + * 3. Build the Skyflow client with the chosen configuration and set log level. + * 4. Example of changing the log level from ERROR (default) to INFO. + */ +public class ChangeLogLevel { + public static void main(String[] args) throws SkyflowException { + // Step 1: Set up credentials - either pass token or use credentials string + // In this case, we are using a Bearer token for authentication + Credentials credentials = new Credentials(); + credentials.setToken(""); // Replace with actual Bearer token + + // Step 2: Define the Vault configuration + // Configure the vault with necessary details like vault ID, cluster ID, and environment + VaultConfig config = new VaultConfig(); + config.setVaultId(""); // Replace with actual Vault ID (primary vault) + config.setClusterId(""); // Replace with actual Cluster ID (from vault URL) + config.setEnv(Env.PROD); // Set the environment (default is PROD) + config.setCredentials(credentials); // Set credentials for the vault (either token or credentials) + + // Step 3: Define additional Skyflow credentials (optional, if needed for credentials string) + // Create a JSON object to hold your Skyflow credentials + JsonObject credentialsObject = new JsonObject(); + credentialsObject.addProperty("clientID", ""); // Replace with your client ID + credentialsObject.addProperty("clientName", ""); // Replace with your client name + credentialsObject.addProperty("TokenURI", ""); // Replace with your token URI + credentialsObject.addProperty("keyID", ""); // Replace with your key ID + credentialsObject.addProperty("privateKey", ""); // Replace with your private key -- `OFF`: + // Convert the credentials object to a string format to be used for generating a Bearer Token + Credentials skyflowCredentials = new Credentials(); + skyflowCredentials.setCredentialsString(credentialsObject.toString()); // Set credentials string - `LogLevel.OFF` can be used to turn off all logging from the skyflow-java SDK. + // Step 4: Build the Skyflow client with the chosen configuration and log level + Skyflow skyflowClient = Skyflow.builder() + .addVaultConfig(config) // Add the Vault configuration + .addSkyflowCredentials(skyflowCredentials) // Use Skyflow credentials if no token is passed + .setLogLevel(LogLevel.INFO) // Set log level to INFO (default is ERROR) + .build(); // Build the Skyflow client -`Note`: The ranking of logging levels is as follows : `DEBUG` < `INFO` < `WARN` < `ERROR`. + // Now, the Skyflow client is ready to use with the specified log level and credentials + System.out.println("Skyflow client has been successfully configured with log level: INFO."); + } +} +``` -## Reporting a Vulnerability +# Reporting a Vulnerability -If you discover a potential security issue in this project, please reach out to us at security@skyflow.com. Please do -not create public GitHub issues or Pull Requests, as malicious actors could potentially view them. +If you discover a potential security issue in this project, please reach out to us at **security@skyflow.com**. Please do not create public GitHub issues or Pull Requests, as malicious actors could potentially view them. From ce8278e3d54fca1bd63aa3b482dfe42964334384 Mon Sep 17 00:00:00 2001 From: skyflow-vivek Date: Fri, 14 Feb 2025 14:50:02 +0000 Subject: [PATCH 4/9] [AUTOMATED] Private Release 2.0.0-beta.1-dev-1284f08 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 99d337e7..6ba77d02 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.skyflow skyflow-java - 1.15.0-dev.27ca248 + 2.0.0-beta.1-dev.1284f08 jar ${project.groupId}:${project.artifactId} From 0b69c49cceb37a45cb7233cd580bdcfddf57499c Mon Sep 17 00:00:00 2001 From: skyflow-vivek Date: Mon, 17 Feb 2025 16:47:53 +0530 Subject: [PATCH 5/9] SK-1890 Add requestIds in response for continueOnError failures - Add requestId for detokenize failure responses when continueOnError is true - Add requestId for insert failure responses when continueOnError is true --- .../java/com/skyflow/utils/Constants.java | 1 + .../vault/controller/VaultController.java | 24 +++++++++++++------ .../tokens/DetokenizeRecordResponse.java | 10 ++++++++ .../com/skyflow/vault/data/InsertTests.java | 10 ++++++-- .../skyflow/vault/tokens/DetokenizeTests.java | 8 ++++--- 5 files changed, 41 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/skyflow/utils/Constants.java b/src/main/java/com/skyflow/utils/Constants.java index 3ce68c79..b0620609 100644 --- a/src/main/java/com/skyflow/utils/Constants.java +++ b/src/main/java/com/skyflow/utils/Constants.java @@ -24,4 +24,5 @@ public final class Constants { public static final String SDK_METRIC_RUNTIME_DETAILS_PREFIX = "Java@"; public static final String SDK_AUTH_HEADER_KEY = "x-skyflow-authorization"; public static final String SDK_METRICS_HEADER_KEY = "sky-metadata"; + public static final String REQUEST_ID_HEADER_KEY = "x-request-id"; } diff --git a/src/main/java/com/skyflow/vault/controller/VaultController.java b/src/main/java/com/skyflow/vault/controller/VaultController.java index 7744dfd8..f2130706 100644 --- a/src/main/java/com/skyflow/vault/controller/VaultController.java +++ b/src/main/java/com/skyflow/vault/controller/VaultController.java @@ -7,9 +7,11 @@ import com.skyflow.enums.RedactionType; import com.skyflow.errors.SkyflowException; import com.skyflow.generated.rest.ApiException; +import com.skyflow.generated.rest.ApiResponse; import com.skyflow.generated.rest.models.*; import com.skyflow.logs.ErrorLogs; import com.skyflow.logs.InfoLogs; +import com.skyflow.utils.Constants; import com.skyflow.utils.logger.LogUtil; import com.skyflow.utils.validations.Validations; import com.skyflow.vault.data.*; @@ -18,6 +20,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Map; public final class VaultController extends VaultClient { private static final Gson gson = new GsonBuilder().serializeNulls().create(); @@ -111,7 +114,7 @@ private static synchronized HashMap getFormattedQueryRecord(V1Fi public InsertResponse insert(InsertRequest insertRequest) throws SkyflowException { LogUtil.printInfoLog(InfoLogs.INSERT_TRIGGERED.getLog()); V1InsertRecordResponse bulkInsertResult = null; - V1BatchOperationResponse batchInsertResult = null; + ApiResponse batchInsertResult = null; ArrayList> insertedFields = new ArrayList<>(); ArrayList> errorFields = new ArrayList<>(); Boolean continueOnError = insertRequest.getContinueOnError(); @@ -121,15 +124,18 @@ public InsertResponse insert(InsertRequest insertRequest) throws SkyflowExceptio setBearerToken(); if (continueOnError) { RecordServiceBatchOperationBody insertBody = super.getBatchInsertRequestBody(insertRequest); - batchInsertResult = super.getRecordsApi().recordServiceBatchOperation(super.getVaultConfig().getVaultId(), insertBody); + batchInsertResult = super.getRecordsApi().recordServiceBatchOperationWithHttpInfo(super.getVaultConfig().getVaultId(), insertBody); LogUtil.printInfoLog(InfoLogs.INSERT_REQUEST_RESOLVED.getLog()); - List records = batchInsertResult.getResponses(); + Map> responseHeaders = batchInsertResult.getHeaders(); + String requestId = responseHeaders.get(Constants.REQUEST_ID_HEADER_KEY).get(0); + List records = batchInsertResult.getData().getResponses(); for (int index = 0; index < records.size(); index++) { Object record = records.get(index); HashMap insertRecord = getFormattedBatchInsertRecord(record, index); if (insertRecord.containsKey("skyflowId")) { insertedFields.add(insertRecord); } else { + insertRecord.put("requestId", requestId); errorFields.add(insertRecord); } } @@ -156,7 +162,7 @@ public InsertResponse insert(InsertRequest insertRequest) throws SkyflowExceptio public DetokenizeResponse detokenize(DetokenizeRequest detokenizeRequest) throws SkyflowException { LogUtil.printInfoLog(InfoLogs.DETOKENIZE_TRIGGERED.getLog()); - V1DetokenizeResponse result = null; + ApiResponse result = null; ArrayList detokenizedFields = new ArrayList<>(); ArrayList errorRecords = new ArrayList<>(); try { @@ -164,15 +170,19 @@ public DetokenizeResponse detokenize(DetokenizeRequest detokenizeRequest) throws Validations.validateDetokenizeRequest(detokenizeRequest); setBearerToken(); V1DetokenizePayload payload = super.getDetokenizePayload(detokenizeRequest); - result = super.getTokensApi().recordServiceDetokenize(super.getVaultConfig().getVaultId(), payload); + result = super.getTokensApi().recordServiceDetokenizeWithHttpInfo(super.getVaultConfig().getVaultId(), payload); LogUtil.printInfoLog(InfoLogs.DETOKENIZE_REQUEST_RESOLVED.getLog()); - List records = result.getRecords(); + Map> responseHeaders = result.getHeaders(); + String requestId = responseHeaders.get(Constants.REQUEST_ID_HEADER_KEY).get(0); + List records = result.getData().getRecords(); + if (records != null) { for (V1DetokenizeRecordResponse record : records) { - DetokenizeRecordResponse recordResponse = new DetokenizeRecordResponse(record); if (record.getError() != null) { + DetokenizeRecordResponse recordResponse = new DetokenizeRecordResponse(record, requestId); errorRecords.add(recordResponse); } else { + DetokenizeRecordResponse recordResponse = new DetokenizeRecordResponse(record); detokenizedFields.add(recordResponse); } } diff --git a/src/main/java/com/skyflow/vault/tokens/DetokenizeRecordResponse.java b/src/main/java/com/skyflow/vault/tokens/DetokenizeRecordResponse.java index 198034a7..0904d6b6 100644 --- a/src/main/java/com/skyflow/vault/tokens/DetokenizeRecordResponse.java +++ b/src/main/java/com/skyflow/vault/tokens/DetokenizeRecordResponse.java @@ -7,12 +7,18 @@ public class DetokenizeRecordResponse { private final String value; private final String type; private final String error; + private final String requestId; public DetokenizeRecordResponse(V1DetokenizeRecordResponse record) { + this(record, null); + } + + public DetokenizeRecordResponse(V1DetokenizeRecordResponse record, String requestId) { this.token = record.getToken(); this.value = record.getValue().isEmpty() ? null : record.getValue(); this.type = record.getValueType().getValue().equals("NONE") ? null : record.getValueType().getValue(); this.error = record.getError(); + this.requestId = requestId; } public String getError() { @@ -30,4 +36,8 @@ public String getValue() { public String getType() { return type; } + + public String getRequestId() { + return requestId; + } } \ No newline at end of file diff --git a/src/test/java/com/skyflow/vault/data/InsertTests.java b/src/test/java/com/skyflow/vault/data/InsertTests.java index 573ac5e4..00399f00 100644 --- a/src/test/java/com/skyflow/vault/data/InsertTests.java +++ b/src/test/java/com/skyflow/vault/data/InsertTests.java @@ -22,6 +22,7 @@ public class InsertTests { private static final String INVALID_EXCEPTION_THROWN = "Should not have thrown any exception"; private static final String EXCEPTION_NOT_THROWN = "Should have thrown an exception"; + private static final String requestId = "95be08fc-4d13-4335-8b8d-24e85d53ed1d"; private static String vaultID = null; private static String clusterID = null; private static String table = null; @@ -408,6 +409,11 @@ public void testEmptyValueInTokensInInsertRequestValidations() { public void testInsertResponse() { try { ArrayList> errorFields = new ArrayList<>(); + HashMap error = new HashMap<>(); + error.put("requestIndex", 0); + error.put("requestId", requestId); + error.put("error", "Insert failed"); + errorFields.add(error); values.add(valueMap); values.add(valueMap); InsertResponse response = new InsertResponse(values, errorFields); @@ -416,9 +422,9 @@ public void testInsertResponse() { "\"test_column_2\":\"test_value_2\"}," + "{\"test_column_1\":\"test_value_1\"," + "\"test_column_2\":\"test_value_2\"}]" + - ",\"errors\":" + errorFields + "}"; + ",\"errors\":[{\"requestIndex\":0,\"requestId\":\"" + requestId + "\",\"error\":\"Insert failed\"}]}"; Assert.assertEquals(2, response.getInsertedFields().size()); - Assert.assertTrue(response.getErrors().isEmpty()); + Assert.assertEquals(1, response.getErrors().size()); Assert.assertEquals(responseString, response.toString()); } catch (Exception e) { Assert.fail(INVALID_EXCEPTION_THROWN); diff --git a/src/test/java/com/skyflow/vault/tokens/DetokenizeTests.java b/src/test/java/com/skyflow/vault/tokens/DetokenizeTests.java index aea06095..44bcf2a5 100644 --- a/src/test/java/com/skyflow/vault/tokens/DetokenizeTests.java +++ b/src/test/java/com/skyflow/vault/tokens/DetokenizeTests.java @@ -19,6 +19,7 @@ public class DetokenizeTests { private static final String INVALID_EXCEPTION_THROWN = "Should not have thrown any exception"; private static final String EXCEPTION_NOT_THROWN = "Should have thrown an exception"; + private static final String requestId = "95be08fc-4d13-4335-8b8d-24e85d53ed1d"; private static ArrayList detokenizeData = null; private static DetokenizeData maskedRedactionRecord = null; private static DetokenizeData plainRedactionRecord = null; @@ -156,7 +157,7 @@ public void testDetokenizeResponse() { record2.setToken("3456-7890-1234-5678"); record2.setValue(""); record2.setError("Invalid token"); - DetokenizeRecordResponse error = new DetokenizeRecordResponse(record2); + DetokenizeRecordResponse error = new DetokenizeRecordResponse(record2, requestId); ArrayList fields = new ArrayList<>(); fields.add(field); @@ -170,14 +171,15 @@ public void testDetokenizeResponse() { String responseString = "{\"detokenizedFields\":[{" + "\"token\":\"1234-5678-9012-3456\",\"value\":\"4111111111111111\",\"type\":\"STRING\"}," + "{\"token\":\"1234-5678-9012-3456\",\"value\":\"4111111111111111\",\"type\":\"STRING\"}]," + - "\"errors\":[{\"token\":\"3456-7890-1234-5678\",\"error\":\"Invalid token\"}," + - "{\"token\":\"3456-7890-1234-5678\",\"error\":\"Invalid token\"}]}"; + "\"errors\":[{\"token\":\"3456-7890-1234-5678\",\"error\":\"Invalid token\",\"requestId\":\"" + requestId + "\"}," + + "{\"token\":\"3456-7890-1234-5678\",\"error\":\"Invalid token\",\"requestId\":\"" + requestId + "\"}]}"; Assert.assertEquals(2, response.getDetokenizedFields().size()); Assert.assertEquals(2, response.getErrors().size()); Assert.assertEquals("1234-5678-9012-3456", response.getDetokenizedFields().get(0).getToken()); Assert.assertEquals("4111111111111111", response.getDetokenizedFields().get(0).getValue()); Assert.assertEquals("STRING", response.getDetokenizedFields().get(0).getType()); Assert.assertEquals("Invalid token", response.getErrors().get(0).getError()); + Assert.assertEquals(requestId, response.getErrors().get(0).getRequestId()); Assert.assertEquals(responseString, response.toString()); } catch (Exception e) { Assert.fail(INVALID_EXCEPTION_THROWN); From ad0215a22588fde42e1286ebd46aa903fa17241d Mon Sep 17 00:00:00 2001 From: skyflow-vivek Date: Thu, 20 Feb 2025 15:25:40 +0000 Subject: [PATCH 6/9] [AUTOMATED] Private Release 2.0.0-beta.1-dev-b6b25c8 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6ba77d02..21f3189b 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.skyflow skyflow-java - 2.0.0-beta.1-dev.1284f08 + 2.0.0-beta.1-dev.b6b25c8 jar ${project.groupId}:${project.artifactId} From 6b8c27da32c541c4e8bca46cf1e052293782e592 Mon Sep 17 00:00:00 2001 From: skyflow-vivek Date: Tue, 25 Feb 2025 13:57:47 +0530 Subject: [PATCH 7/9] SK-1900 Improve debugging errors in connections --- .../com/skyflow/errors/SkyflowException.java | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/skyflow/errors/SkyflowException.java b/src/main/java/com/skyflow/errors/SkyflowException.java index 1db1ed19..a455521d 100644 --- a/src/main/java/com/skyflow/errors/SkyflowException.java +++ b/src/main/java/com/skyflow/errors/SkyflowException.java @@ -41,10 +41,10 @@ public SkyflowException(int httpCode, Throwable cause, Map> super(cause); this.httpCode = httpCode; setRequestId(responseHeaders); - setResponseBody(responseBody); + setResponseBody(responseBody, responseHeaders); } - private void setResponseBody(String responseBody) { + private void setResponseBody(String responseBody, Map> responseHeaders) { try { if (responseBody != null) { this.responseBody = JsonParser.parseString(responseBody).getAsJsonObject(); @@ -52,7 +52,7 @@ private void setResponseBody(String responseBody) { setGrpcCode(); setHttpStatus(); setMessage(); - setDetails(); + setDetails(responseHeaders); } } } catch (JsonSyntaxException e) { @@ -86,9 +86,19 @@ private void setHttpStatus() { this.httpStatus = statusElement == null ? null : statusElement.getAsString(); } - private void setDetails() { + private void setDetails(Map> responseHeaders) { JsonElement detailsElement = ((JsonObject) responseBody.get("error")).get("details"); - this.details = detailsElement == null ? null : detailsElement.getAsJsonArray(); + List errorFromClientHeader = responseHeaders.get("error-from-client"); + if (detailsElement != null) { + this.details = detailsElement.getAsJsonArray(); + } + if (errorFromClientHeader != null) { + this.details = this.details == null ? new JsonArray() : this.details; + String errorFromClient = errorFromClientHeader.get(0); + JsonObject detailObject = new JsonObject(); + detailObject.addProperty("errorFromClient", errorFromClient); + this.details.add(detailObject); + } } public int getHttpCode() { From 0aaf4d246f7e9b32d3ca6af000b38a8ecfc053df Mon Sep 17 00:00:00 2001 From: skyflow-vivek Date: Fri, 28 Feb 2025 05:46:36 +0000 Subject: [PATCH 8/9] [AUTOMATED] Private Release 2.0.0-beta.1-dev-ea71c1d --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 21f3189b..b3aa8170 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.skyflow skyflow-java - 2.0.0-beta.1-dev.b6b25c8 + 2.0.0-beta.1-dev.ea71c1d jar ${project.groupId}:${project.artifactId} From 7c12079bff1e51100f21e98d4a1cc3a70287f952 Mon Sep 17 00:00:00 2001 From: skyflow-vivek Date: Thu, 27 Mar 2025 07:05:59 +0000 Subject: [PATCH 9/9] [AUTOMATED] Private Release 2.0.0-beta.1-dev-9f386ac --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b3aa8170..0f61f9c3 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.skyflow skyflow-java - 2.0.0-beta.1-dev.ea71c1d + 2.0.0-beta.1-dev.9f386ac jar ${project.groupId}:${project.artifactId}