diff --git a/ojdbc-provider-aws/README.md b/ojdbc-provider-aws/README.md index 761ebcc9..4d533f8e 100644 --- a/ojdbc-provider-aws/README.md +++ b/ojdbc-provider-aws/README.md @@ -68,11 +68,12 @@ The {S3-URI} can be obtained from the Amazon S3 console and follows this naming ### JSON Payload format -There are 3 fixed values that are looked at the root level. +There are 4 fixed values that are looked at the root level. - connect_descriptor (required) - user (optional) - password (optional) +- wallet_location (optional) The rest are dependent on the driver, in our case `/jdbc`. The key-value pairs that are with sub-prefix `/jdbc` will be applied to a DataSource. The key values are constant keys which are equivalent to the properties defined in the [OracleConnection](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html) interface. @@ -93,6 +94,11 @@ And the JSON Payload for the file **payload_ojdbc_objectstorage.json** in **mybu "value": "test-secret", "field_name": "" // Optional: Only needed when the secret is structured and contains multiple key-value pairs. }, + "wallet_location": { + "type": "awssecretsmanager", + "value": "wallet-secret", + "field_name": "" // Optional: Only needed when the secret is structured and contains multiple key-value pairs. + }, "jdbc": { "oracle.jdbc.ReadTimeout": 1000, "defaultRowPrefetch": 20, @@ -117,32 +123,52 @@ The sample code below executes as expected with the previous configuration. For the JSON type of provider (AWS S3, AWS Secrets Manager, HTTP/HTTPS, File) the password is an object itself with the following spec: -- type +- `type` - Mandatory - Possible values - - ocivault - - azurevault - - base64 - - awssecretsmanager -- value + - `ocivault` (OCI Vault) + - `azurevault` (Azure Key Vault) + - `base64` (Base64) + - `awssecretsmanager` (AWS Secrets Manager) + - `hcpvaultdedicated` (HCP Vault Dedicated) + - `hcpvaultsecret` (HCP Vault Secrets) + - `gcpsecretmanager` (GCP Secret Manager) +- `value` - Mandatory - Possible values - OCID of the secret (if ocivault) - Azure Key Vault URI (if azurevault) - Base64 Encoded password (if base64) - AWS Secret name (if awssecretsmanager) -- field_name + - Secret path (if hcpvaultdedicated) + - Secret name (if hcpvaultsecret) + - Secret name (if gcpsecretmanager) +- `field_name` - Optional - Description: Specifies the key within the secret JSON object from which to extract the password value. If the secret JSON contains multiple key-value pairs, field_name must be provided to unambiguously select the desired secret value. If the secret contains only a single key-value pair and field_name is not provided, that sole value will be used. If the secret is provided as plain text (i.e., not structured as a JSON object), no field_name is required. -- authentication +- `authentication` - Optional - Possible Values - method - optional parameters (depends on the cloud provider). +### Wallet_location JSON Object + +The `oracle.net.wallet_location` connection property is not allowed in the `jdbc` object due to security reasons. Instead, users should use the `wallet_location` object to specify the wallet in the configuration. + +For the JSON type of provider (AWS S3, HTTPS, File) the wallet_location is an object itself with the same spec as the [password JSON object](#password-json-object) mentioned above. + +The value stored in the secret should be the Base64 representation of the bytes in `cwallet.sso`. This is equivalent to setting the `oracle.net.wallet_location` connection property in a regular JDBC application using the following format: + +``` +data:;base64, +``` + +*Note: When storing a wallet in AWS Secrets Manager, store the raw Base64-encoded wallet bytes directly. The provider will automatically detect and handle the encoding correctly. + ## AWS Secrets Manager Config Provider Apart from AWS S3, users can also store JSON Payload in the content of AWS Secrets Manager secret. Users need to indicate the secret name: diff --git a/ojdbc-provider-aws/src/main/java/oracle/jdbc/provider/aws/configuration/AwsJsonSecretsManagerProvider.java b/ojdbc-provider-aws/src/main/java/oracle/jdbc/provider/aws/configuration/AwsJsonSecretsManagerProvider.java index 889e7900..d3bf7b9f 100644 --- a/ojdbc-provider-aws/src/main/java/oracle/jdbc/provider/aws/configuration/AwsJsonSecretsManagerProvider.java +++ b/ojdbc-provider-aws/src/main/java/oracle/jdbc/provider/aws/configuration/AwsJsonSecretsManagerProvider.java @@ -42,12 +42,11 @@ import oracle.jdbc.provider.parameter.ParameterSet; import oracle.jdbc.spi.OracleConfigurationSecretProvider; -import java.nio.charset.StandardCharsets; -import java.util.Base64; import java.util.Map; import static oracle.jdbc.provider.aws.configuration.AwsConfigurationParameters.FIELD_NAME; import static oracle.jdbc.provider.aws.configuration.AwsSecretsManagerConfigurationProvider.PARAMETER_SET_PARSER; +import static oracle.jdbc.provider.util.FileUtils.toBase64EncodedCharArray; public class AwsJsonSecretsManagerProvider implements OracleConfigurationSecretProvider { @@ -96,9 +95,7 @@ public char[] getSecret(Map map) { String extractedSecret = AwsSecretExtractor.extractSecret(secretString, fieldName); - return Base64.getEncoder() - .encodeToString(extractedSecret.getBytes(StandardCharsets.UTF_8)) - .toCharArray(); + return toBase64EncodedCharArray(extractedSecret); } @Override diff --git a/ojdbc-provider-azure/README.md b/ojdbc-provider-azure/README.md index cb1a41e2..9c6f24a0 100644 --- a/ojdbc-provider-azure/README.md +++ b/ojdbc-provider-azure/README.md @@ -103,6 +103,51 @@ The sample code below executes as expected with the previous configuration (and if (rs.next()) System.out.println("select sysdate from dual: " + rs.getString(1)); ``` +### Password JSON Object + +For the JSON type of provider (Azure App Configuration, Azure Key Vault, HTTP/HTTPS, File) the password is an object itself with the following spec: + +- `type` + - Mandatory + - Possible values + - `azurevault` (Azure Key Vault) + - `ocivault` (OCI Vault) + - `base64` (Base64) + - `awssecretsmanager` (AWS Secrets Manager) + - `hcpvaultdedicated` (HCP Vault Dedicated) + - `hcpvaultsecret` (HCP Vault Secrets) + - `gcpsecretmanager` (GCP Secret Manager) +- `value` + - Mandatory + - Possible values + - Azure Key Vault URI (if azurevault) + - OCID of the secret (if ocivault) + - Base64 Encoded password (if base64) + - AWS Secret name (if awssecretsmanager) + - Secret path (if hcpvaultdedicated) + - Secret name (if hcpvaultsecret) + - Secret name (if gcpsecretmanager) +- `authentication` + - Optional + - Possible Values + - method + - optional parameters (depends on the cloud provider). + +### Wallet_location JSON Object + +The `oracle.net.wallet_location` connection property is not allowed in the `jdbc` object due to security reasons. Instead, users should use the `wallet_location` object to specify the wallet in the configuration. + +For the JSON type of provider (Azure App Configuration, HTTPS, File) the `wallet_location` is an object itself with the same spec as the [password JSON object](#password-json-object) mentioned above. + +The value stored in the secret should be the Base64 representation of the bytes in `cwallet.sso`. This is equivalent to setting the `oracle.net.wallet_location` connection property in a regular JDBC application using the following format: + +``` +data:;base64, +``` + +*Note: When storing a wallet in Azure Key Vault, store the raw Base64-encoded wallet bytes directly. The provider will automatically detect and handle the encoding correctly. + + ## Azure Vault Config Provider Similar to [OCI Vault Config Provider](../ojdbc-provider-oci/README.md#oci-vault-config-provider), JSON Payload can also be stored in the content of Azure Key Vault Secret. The Oracle Data Source uses a new prefix `jdbc:oracle:thin:@config-azurevault://`. Users only need to indicate the Vault Secret’s secret identifier using the following syntax, where option-value pairs separated by `&` are optional authentication parameters that vary by provider: diff --git a/ojdbc-provider-azure/src/main/java/oracle/jdbc/provider/azure/configuration/AzureVaultSecretProvider.java b/ojdbc-provider-azure/src/main/java/oracle/jdbc/provider/azure/configuration/AzureVaultSecretProvider.java index a41fa568..b0e88723 100644 --- a/ojdbc-provider-azure/src/main/java/oracle/jdbc/provider/azure/configuration/AzureVaultSecretProvider.java +++ b/ojdbc-provider-azure/src/main/java/oracle/jdbc/provider/azure/configuration/AzureVaultSecretProvider.java @@ -44,9 +44,10 @@ import oracle.jdbc.provider.parameter.ParameterSet; import oracle.jdbc.provider.parameter.ParameterSetParser; -import java.util.Base64; import java.util.Map; +import static oracle.jdbc.provider.util.FileUtils.toBase64EncodedCharArray; + /** * A provider of Secret values from Azure Key Vault. */ @@ -97,9 +98,7 @@ public char[] getSecret(Map secretProperties) { .getContent() .getValue(); - return Base64.getEncoder() - .encodeToString(secretString.getBytes()) - .toCharArray(); + return toBase64EncodedCharArray(secretString); } /** diff --git a/ojdbc-provider-common/src/main/java/oracle/jdbc/provider/util/FileUtils.java b/ojdbc-provider-common/src/main/java/oracle/jdbc/provider/util/FileUtils.java index db15ca6e..84cc27b5 100644 --- a/ojdbc-provider-common/src/main/java/oracle/jdbc/provider/util/FileUtils.java +++ b/ojdbc-provider-common/src/main/java/oracle/jdbc/provider/util/FileUtils.java @@ -38,6 +38,7 @@ package oracle.jdbc.provider.util; +import java.nio.charset.StandardCharsets; import java.util.Base64; /** @@ -67,4 +68,25 @@ public static byte[] decodeIfBase64(byte[] input) { return isBase64Encoded(input) ? Base64.getDecoder().decode(input) : input; } + + /** + * Converts a secret string to a Base64-encoded char array. + * If the secret is already Base64-encoded, it is returned as a char array. + * Otherwise, it is encoded to Base64. + * + * @param secretString The secret string to process + * @return A char array containing the Base64-encoded secret, + * or null if the input is null + */ + public static char[] toBase64EncodedCharArray(String secretString) { + if (secretString == null) { + return null; + } + byte[] secretBytes = secretString.getBytes(StandardCharsets.UTF_8); + if (isBase64Encoded(secretBytes)) { + return secretString.toCharArray(); + } else { + return Base64.getEncoder().encodeToString(secretBytes).toCharArray(); + } + } } diff --git a/ojdbc-provider-gcp/README.md b/ojdbc-provider-gcp/README.md index 37713445..1831c134 100644 --- a/ojdbc-provider-gcp/README.md +++ b/ojdbc-provider-gcp/README.md @@ -109,6 +109,10 @@ And the JSON Payload for the file **payload_ojdbc_objectstorage.json** in the ** "type": "gcpsecretmanager", "value": "projects/138028249883/secrets/test-secret/versions/1" }, + "wallet_location": { + "type": "gcpsecretmanager", + "value": "projects/myproject/secrets/wallet-secret/versions/1" + }, "jdbc": { "oracle.jdbc.ReadTimeout": 1000, "defaultRowPrefetch": 20, @@ -133,27 +137,50 @@ The sample code below executes as expected with the previous configuration. For the JSON type of provider (GCP Object Storage, HTTP/HTTPS, File) the password is an object itself with the following spec: -- type +- `type` - Mandatory - Possible values - - ocivault - - azurevault - - base64 - - gcpsecretmanager -- value + - `gcpsecretmanager` (GCP Secret Manager) + - `ocivault` (OCI Vault) + - `azurevault` (Azure Key Vault) + - `base64` (Base64) + - `awssecretsmanager` (AWS Secrets Manager) + - `hcpvaultdedicated` (HCP Vault Dedicated) + - `hcpvaultsecret` (HCP Vault Secrets) +- `value` - Mandatory - Possible values + - Secret name (if gcpsecretmanager) - OCID of the secret (if ocivault) - Azure Key Vault URI (if azurevault) - Base64 Encoded password (if base64) - - GCP resource name (if gcpsecretmanager) - - Text -- authentication + - AWS Secret name (if awssecretsmanager) + - Secret path (if hcpvaultdedicated) + - Secret name (if hcpvaultsecret) +- `authentication` - Optional - Possible Values - method - optional parameters (depends on the cloud provider). +### Wallet_location JSON Object + +The `oracle.net.wallet_location` connection property is not allowed in the "jdbc" object due to security reasons. Instead, users should use the `wallet_location object to specify the wallet in the configuration. + +For the JSON type of provider (GCP Cloud Storage, HTTPS, File) the `wallet_location` is an object itself with the same spec as the [password JSON object](#password-json-object) mentioned above. + +The value stored in the secret can be either: + + - The Base64 representation of the bytes in cwallet.sso. + - The raw bytes of the cwallet.sso file, stored as an imported file. + +In both cases, the provider will automatically handle the content. If the secret contains raw bytes (e.g., an imported cwallet.sso file), the provider will perform Base64 encoding as needed. The resulting format is equivalent to setting the oracle.net.wallet_location connection property in a regular JDBC application using the following format: +``` +data:;base64, +``` + +*Note: When storing a wallet in GCP Secret Manager, you can either store the raw bytes of the cwallet.sso file directly or provide the Base64-encoded string. The provider will detect the format and handle the encoding appropriately. + ## GCP Secret Manager Config Provider Apart from GCP Cloud Storage, users can also store JSON Payload in the content of GCP Secret Manager secret. Users need to indicate the resource name: diff --git a/ojdbc-provider-hashicorp/README.md b/ojdbc-provider-hashicorp/README.md index 148a1683..7af58e69 100644 --- a/ojdbc-provider-hashicorp/README.md +++ b/ojdbc-provider-hashicorp/README.md @@ -450,11 +450,12 @@ jdbc:oracle:thin:@config-hcpvaultsecret://secret-name?HCP_APP_NAME=app-name&key= ### JSON Payload format -There are 3 fixed values that are looked at the root level: +There are 4 fixed values that are looked at the root level: - `connect_descriptor` (required) - `user` (optional) - `password` (optional) +- `wallet_location` (optional) The rest are dependent on the driver, in our case `/jdbc`. The key-value pairs that are under the `/jdbc` prefix will be applied to a `DataSource`. These keys correspond to the properties defined in the [OracleConnection](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html) interface. @@ -473,7 +474,12 @@ And the JSON Payload for the secret **test_config** stored in the HCP Vault Dedi "password": { "type": "hcpvaultdedicated", "value": "/v1/namespace/secret/data/password", - "field_name": "db-password" + "field_name": "db-password" // Optional: Only needed when the secret is structured and contains multiple key-value pairs. + }, + "wallet_location": { + "type": "hcpvaultdedicated", + "value": "/v1/namespace/secret/data/wallet", + "field_name": "wallet_field" // Optional: Only needed when the secret is structured and contains multiple key-value pairs. }, "jdbc": { "oracle.jdbc.ReadTimeout": 1000, @@ -509,6 +515,10 @@ And the JSON Payload for a secret stored within the application app_name in the "type": "hcpvaultsecret", "value": "secret-name" }, + "wallet_location": { + "type": "hcpvaultsecret", + "value": "wallet-secret" + }, "jdbc": { "oracle.jdbc.ReadTimeout": 1000, "defaultRowPrefetch": 20, @@ -533,24 +543,27 @@ The sample code below executes as expected with the previous configuration. For the JSON type of provider (HCP Vault Dedicated, HCP Vault Secrets, HTTP/HTTPS, File), the password is an object itself with the following spec: -- type +- `type` - Mandatory - Possible values - - ocivault - - azurevault - - base64 - - hcpvaultdedicated - - hcpvaultsecret -- value + - `hcpvaultdedicated` (HCP Vault Dedicated) + - `hcpvaultsecret` (HCP Vault Secrets) + - `ocivault` (OCI Vault) + - `azurevault` (Azure Key Vault) + - `base64` (Base64) + - `awssecretsmanager` (AWS Secrets Manager) + - `gcpsecretmanager` (GCP Secret Manager) +- `value` - Mandatory - Possible values - - OCID of the secret (if ocivault) - - Azure Key Vault URI (if azurevault) - - Base64 Encoded password (if base64) - - Secret path (if hcpvaultdedicated) - - Secret name (if hcpvaultsecret) - - Text -- field_name (HCP Vault Dedicated only) + - Secret path (if hcpvaultdedicated) + - Secret name (if hcpvaultsecret) + - OCID of the secret (if ocivault) + - Azure Key Vault URI (if azurevault) + - Base64 Encoded password (if base64) + - AWS Secret name (if awssecretsmanager) + - Secret name (if gcpsecretmanager) +- `field_name` (HCP Vault Dedicated only) - Optional - Description: Specifies the key within the secret JSON object to retrieve the password value. For example, if the secret contains `{ "db-password": "mypassword" }`, @@ -559,12 +572,26 @@ For the JSON type of provider (HCP Vault Dedicated, HCP Vault Secrets, HTTP/HTTP - If `field_name` is **specified**, its corresponding value is extracted. - If the **secret contains only one key-value pair**, that value is **automatically used**. - If `field_name` is **missing** and **multiple keys exist**, an **error is thrown**. -- authentication +- `authentication` - Optional - Possible Values - method - optional parameters (depends on the cloud provider). +### Wallet_location JSON Object + +The `oracle.net.wallet_location` connection property is not allowed in the `jdbc` object due to security reasons. Instead, users should use the `wallet_location` object to specify the wallet in the configuration. + +For the JSON type of provider (HCP Vault Dedicated, HCP Vault Secrets, HTTPS, File) the `wallet_location` is an object itself with the same spec as the [password JSON object](#password-json-object) mentioned above. + +The value stored in the secret should be the Base64 representation of the bytes in `cwallet.sso`. This is equivalent to setting the `oracle.net.wallet_location` connection property in a regular JDBC application using the following format: + +``` +data:;base64, +``` + +*Note: When storing a wallet in HCP Vault Dedicated or HCP Vault Secrets, store the raw Base64-encoded wallet bytes directly. The provider will automatically detect and handle the encoding correctly. + ## Resource Providers ### Dedicated Vault Username Provider diff --git a/ojdbc-provider-hashicorp/src/main/java/oracle/jdbc/provider/hashicorp/hcpvaultdedicated/configuration/DedicatedVaultJsonSecretProvider.java b/ojdbc-provider-hashicorp/src/main/java/oracle/jdbc/provider/hashicorp/hcpvaultdedicated/configuration/DedicatedVaultJsonSecretProvider.java index 731d54ff..abe0a2d3 100644 --- a/ojdbc-provider-hashicorp/src/main/java/oracle/jdbc/provider/hashicorp/hcpvaultdedicated/configuration/DedicatedVaultJsonSecretProvider.java +++ b/ojdbc-provider-hashicorp/src/main/java/oracle/jdbc/provider/hashicorp/hcpvaultdedicated/configuration/DedicatedVaultJsonSecretProvider.java @@ -44,12 +44,12 @@ import oracle.jdbc.spi.OracleConfigurationSecretProvider; import oracle.sql.json.OracleJsonObject; -import java.util.Base64; import java.util.Map; import static oracle.jdbc.provider.hashicorp.hcpvaultdedicated.authentication.DedicatedVaultParameters.FIELD_NAME; import static oracle.jdbc.provider.hashicorp.hcpvaultdedicated.authentication.DedicatedVaultParameters.PARAMETER_SET_PARSER; import static oracle.jdbc.provider.hashicorp.util.JsonUtil.extractSecret; +import static oracle.jdbc.provider.util.FileUtils.toBase64EncodedCharArray; /** *

@@ -98,9 +98,7 @@ public char[] getSecret(Map map) { String fieldName = parameterSet.getOptional(FIELD_NAME); String extractedSecret = extractSecret(secretJsonObj, fieldName); - return Base64.getEncoder() - .encodeToString(extractedSecret.getBytes()) - .toCharArray(); + return toBase64EncodedCharArray(extractedSecret); } @Override diff --git a/ojdbc-provider-hashicorp/src/main/java/oracle/jdbc/provider/hashicorp/hcpvaultsecret/configuration/HcpVaultJsonVaultProvider.java b/ojdbc-provider-hashicorp/src/main/java/oracle/jdbc/provider/hashicorp/hcpvaultsecret/configuration/HcpVaultJsonVaultProvider.java index af21af4c..48249dfa 100644 --- a/ojdbc-provider-hashicorp/src/main/java/oracle/jdbc/provider/hashicorp/hcpvaultsecret/configuration/HcpVaultJsonVaultProvider.java +++ b/ojdbc-provider-hashicorp/src/main/java/oracle/jdbc/provider/hashicorp/hcpvaultsecret/configuration/HcpVaultJsonVaultProvider.java @@ -40,13 +40,14 @@ import oracle.jdbc.provider.hashicorp.hcpvaultsecret.secrets.HcpVaultSecretsManagerFactory; import oracle.jdbc.provider.parameter.ParameterSet; + import oracle.jdbc.spi.OracleConfigurationSecretProvider; -import java.nio.charset.StandardCharsets; -import java.util.Base64; import java.util.Map; import static oracle.jdbc.provider.hashicorp.hcpvaultsecret.authentication.HcpVaultSecretParameters.PARAMETER_SET_PARSER; +import static oracle.jdbc.provider.util.FileUtils.toBase64EncodedCharArray; + /** *

* Implementation of {@link OracleConfigurationSecretProvider} for @@ -83,9 +84,7 @@ public char[] getSecret(Map map) { .request(parameterSet) .getContent(); - String base64Encoded = Base64.getEncoder() - .encodeToString(secretString.getBytes(StandardCharsets.UTF_8)); - return base64Encoded.toCharArray(); + return toBase64EncodedCharArray(secretString); } @Override diff --git a/ojdbc-provider-oci/README.md b/ojdbc-provider-oci/README.md index 0943cb93..d724b3cd 100644 --- a/ojdbc-provider-oci/README.md +++ b/ojdbc-provider-oci/README.md @@ -157,19 +157,21 @@ For the JSON type of provider (OCI Object Storage, HTTPS, File) the password is - `type` - Mandatory - Possible values: - - `ocivault` - - `azurevault` - - `base64` - - `awssecretsmanager` - - `hcpvaultdedicated` - - `hcpvaultsecret` + - `ocivault` (OCI Vault) + - `gcpsecretmanager` (GCP Secret Manager) + - `azurevault` (Azure Key Vault) + - `base64` (Base64) + - `awssecretsmanager` (AWS Secrets Manager) + - `hcpvaultdedicated` (HCP Vault Dedicated) + - `hcpvaultsecret` (HCP Vault Secrets) - `value` - Mandatory - Possible values: - OCID of the secret (if ocivault) + - Secret name (if gcpsecretmanager) - Azure Key Vault URI (if azurevault) - Base64 Encoded password (if base64) - - AWS resource name of the secret (if awssecretsmanager) + - AWS Secret name (if awssecretsmanager) - Secret path (if hcpvaultdedicated) - Secret name (if hcpvaultsecret) - `authentication`