Skip to content

Aws secretsmanager add type and json key support #168

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion ojdbc-provider-aws/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ And the JSON Payload for the file **payload_ojdbc_objectstorage.json** in **mybu
"user": "scott",
"password": {
"type": "awssecretsmanager",
"value": "test-secret"
"value": "test-secret",
"field_name": "<field-name>" // Optional: Only needed when the secret is structured and contains multiple key-value pairs.
},
"jdbc": {
"oracle.jdbc.ReadTimeout": 1000,
Expand Down Expand Up @@ -113,6 +114,12 @@ For the JSON type of provider (AWS S3, AWS Secrets Manager, HTTP/HTTPS, File) th
- Azure Key Vault URI (if azurevault)
- Base64 Encoded password (if base64)
- AWS Secret name (if awssecretsmanager)
- 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
- Optional
- Possible Values
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ private AwsConfigurationParameters() {}
*/
public static final Parameter<String> KEY = Parameter.create();

/**
* The field name for extracting a specific value from the JSON.
*/
public static final Parameter<String> FIELD_NAME = Parameter.create();

/**
* Configures a {@code builder} to build a parser that recognizes the common
* set of parameters accepted by {@link AwsS3ConfigurationProvider} and
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,23 @@
import oracle.jdbc.provider.aws.secrets.SecretsManagerFactory;
import oracle.jdbc.provider.parameter.ParameterSet;
import oracle.jdbc.spi.OracleConfigurationSecretProvider;
import oracle.sql.json.OracleJsonException;
import oracle.sql.json.OracleJsonFactory;
import oracle.sql.json.OracleJsonObject;

import java.io.ByteArrayInputStream;
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;

public class AwsJsonSecretsManagerProvider
implements OracleConfigurationSecretProvider {

private static final OracleJsonFactory JSON_FACTORY = new OracleJsonFactory();

/**
* {@inheritDoc}
* <p>
Expand All @@ -62,24 +70,59 @@ public class AwsJsonSecretsManagerProvider
* <pre>{@code
* "password": {
* "type": "awssecretsmanager",
* "value": "<secret-name>"
* "value": "<secret-name>",
* "field_name": "<field-name>"
* }
* }</pre>
*
* <p>
* The {@code field_name} parameter indicates the key whose value should
* be extracted as the secret. When there are multiple key-value pairs
* present, specifying this parameter is mandatory in order to
* unambiguously select the desired secret value. If the secret contains
* only a single entry and no {@code field_name} is provided, that sole
* value will be used. In cases where the secret is plain text,
* the {@code field_name} parameter is not required.
* </p>
*
* @param map Map object to be parsed
* @return encoded char array in base64 format that represents the retrieved
* Secret.
*/
@Override
public char[] getSecret(Map<String, String> map) {
ParameterSet parameterSet = PARAMETER_SET_PARSER.parseNamedValues(map);
String fieldName = parameterSet.getOptional(FIELD_NAME);

String secretString = SecretsManagerFactory.getInstance()
.request(parameterSet)
.getContent();

String extractedSecret;

try {
OracleJsonObject jsonObject = JSON_FACTORY.createJsonTextValue(
new ByteArrayInputStream(secretString.getBytes(StandardCharsets.UTF_8)))
.asJsonObject();

if (fieldName != null) {
if (!jsonObject.containsKey(fieldName)) {
throw new IllegalStateException("Field '" + fieldName + "' not found in secret JSON.");
}
extractedSecret = jsonObject.get(fieldName).asJsonString().getString();
} else if (jsonObject.size() == 1) {
extractedSecret = jsonObject.values().iterator().next().asJsonString().getString();
} else {
throw new IllegalStateException(
"FIELD_NAME is required when multiple keys exist in the secret JSON");
}

} catch (OracleJsonException e) {
extractedSecret = secretString;
}

return Base64.getEncoder()
.encodeToString(secretString.getBytes())
.encodeToString(extractedSecret.getBytes(StandardCharsets.UTF_8))
.toCharArray();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@

import oracle.jdbc.driver.configuration.OracleConfigurationParsableProvider;
import oracle.jdbc.provider.aws.secrets.SecretsManagerFactory;
import oracle.jdbc.provider.parameter.Parameter;
import oracle.jdbc.provider.parameter.ParameterSet;
import oracle.jdbc.provider.parameter.ParameterSetParser;
import oracle.jdbc.util.OracleConfigurationCache;
Expand All @@ -64,6 +65,8 @@ public class AwsSecretsManagerConfigurationProvider extends OracleConfigurationP
ParameterSetParser.builder()
.addParameter("value", SecretsManagerFactory.SECRET_NAME)
.addParameter("key", AwsConfigurationParameters.KEY)
.addParameter("type", Parameter.create())
.addParameter("field_name", AwsConfigurationParameters.FIELD_NAME)
.addParameter("AWS_REGION", AwsConfigurationParameters.REGION))
.build();

Expand Down