diff --git a/data-prepper-api/src/main/java/org/opensearch/dataprepper/model/plugin/FailedToUpdatePluginConfigValueException.java b/data-prepper-api/src/main/java/org/opensearch/dataprepper/model/plugin/FailedToUpdatePluginConfigValueException.java new file mode 100644 index 0000000000..41993e6b3b --- /dev/null +++ b/data-prepper-api/src/main/java/org/opensearch/dataprepper/model/plugin/FailedToUpdatePluginConfigValueException.java @@ -0,0 +1,26 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + */ +package org.opensearch.dataprepper.model.plugin; + +/** + * Exception thrown when a secret could not be updated. + * + * @since 2.11 + */ +public class FailedToUpdatePluginConfigValueException extends RuntimeException { + + public FailedToUpdatePluginConfigValueException(final String message) { + super(message); + } + + public FailedToUpdatePluginConfigValueException(final String message, Throwable e) { + super(message, e); + } +} diff --git a/data-prepper-api/src/main/java/org/opensearch/dataprepper/model/plugin/PluginConfigValueTranslator.java b/data-prepper-api/src/main/java/org/opensearch/dataprepper/model/plugin/PluginConfigValueTranslator.java index 2c3a20fbe6..e6ac2525a0 100644 --- a/data-prepper-api/src/main/java/org/opensearch/dataprepper/model/plugin/PluginConfigValueTranslator.java +++ b/data-prepper-api/src/main/java/org/opensearch/dataprepper/model/plugin/PluginConfigValueTranslator.java @@ -1,7 +1,48 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + */ package org.opensearch.dataprepper.model.plugin; +/** + * Interface for a Plugin configuration value translator. + * It translates a string expression that is describing a secret store Id and secret Key in to a secretValue + * extracted from corresponding secret store. + * + * @since 2.0 + */ + public interface PluginConfigValueTranslator { + /** + * Translates a string expression that is describing a secret store Id and secret Key in to a secretValue + * extracted from corresponding secret store. + * Example expression: ${{aws_secrets:secretId:secretKey}} + * + * @param value the string value to translate + * @return the translated object + */ Object translate(final String value); + /** + * Returns the prefix for this translator. + * + * @return the prefix for this translator + */ String getPrefix(); + + /** + * Translates a string expression that is describing a secret store Id and secret Key in to an instance + * of PluginConfigVariable with secretValue extracted from corresponding secret store. Additionally, + * this PluginConfigVariable helps with updating the secret value in the secret store, if required. + * Example expression: ${{aws_secrets:secretId:secretKey}} + * + * @param value the string value to translate + * @return the translated object + */ + PluginConfigVariable translateToPluginConfigVariable(final String value); } diff --git a/data-prepper-api/src/main/java/org/opensearch/dataprepper/model/plugin/PluginConfigVariable.java b/data-prepper-api/src/main/java/org/opensearch/dataprepper/model/plugin/PluginConfigVariable.java new file mode 100644 index 0000000000..32c5bde678 --- /dev/null +++ b/data-prepper-api/src/main/java/org/opensearch/dataprepper/model/plugin/PluginConfigVariable.java @@ -0,0 +1,40 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + */ +package org.opensearch.dataprepper.model.plugin; + +/** + * Interface for a Extension Plugin configuration variable. + * It gives access to the details of a defined extension variable. + * + * @since 2.11 + */ +public interface PluginConfigVariable { + + /** + * Returns the value of this variable. + * + * @return the value of this variable + */ + Object getValue(); + + /** + * If this variable is updatable, this method helps to set a new value for this variable + * + * @param updatedValue the new value to set + */ + void setValue(Object updatedValue); + + /** + * Returns if the variable is updatable. + * + * @return true if this variable is updatable, false otherwise + */ + boolean isUpdatable(); +} diff --git a/data-prepper-api/src/test/java/org/opensearch/dataprepper/model/plugin/FailedToUpdatePluginConfigValueExceptionTest.java b/data-prepper-api/src/test/java/org/opensearch/dataprepper/model/plugin/FailedToUpdatePluginConfigValueExceptionTest.java new file mode 100644 index 0000000000..8956c9aea9 --- /dev/null +++ b/data-prepper-api/src/test/java/org/opensearch/dataprepper/model/plugin/FailedToUpdatePluginConfigValueExceptionTest.java @@ -0,0 +1,43 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + */ +package org.opensearch.dataprepper.model.plugin; + + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.UUID; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +public class FailedToUpdatePluginConfigValueExceptionTest extends RuntimeException { + private String message; + + @BeforeEach + void setUp() { + message = UUID.randomUUID().toString(); + } + + @Test + void testGetMessage_should_return_correct_message() { + FailedToUpdatePluginConfigValueException failedToUpdateSecretException = new FailedToUpdatePluginConfigValueException(message); + assertThat(failedToUpdateSecretException.getMessage(), equalTo(message)); + } + + @Test + void testGetMessage_should_return_correct_message_with_throwable() { + RuntimeException cause = new RuntimeException("testException"); + FailedToUpdatePluginConfigValueException failedToUpdateSecretException = new FailedToUpdatePluginConfigValueException(message, cause); + assertThat(failedToUpdateSecretException.getMessage(), equalTo(message)); + assertThat(failedToUpdateSecretException.getCause(), equalTo(cause)); + } + +} diff --git a/data-prepper-plugin-framework/src/main/java/org/opensearch/dataprepper/plugin/ObjectMapperConfiguration.java b/data-prepper-plugin-framework/src/main/java/org/opensearch/dataprepper/plugin/ObjectMapperConfiguration.java index 513ff3d2fa..d475392b66 100644 --- a/data-prepper-plugin-framework/src/main/java/org/opensearch/dataprepper/plugin/ObjectMapperConfiguration.java +++ b/data-prepper-plugin-framework/src/main/java/org/opensearch/dataprepper/plugin/ObjectMapperConfiguration.java @@ -10,6 +10,7 @@ import com.fasterxml.jackson.databind.module.SimpleModule; import org.opensearch.dataprepper.model.event.EventKey; import org.opensearch.dataprepper.model.event.EventKeyFactory; +import org.opensearch.dataprepper.model.plugin.PluginConfigVariable; import org.opensearch.dataprepper.model.types.ByteCount; import org.opensearch.dataprepper.pipeline.parser.ByteCountDeserializer; import org.opensearch.dataprepper.pipeline.parser.DataPrepperDurationDeserializer; @@ -28,7 +29,7 @@ public class ObjectMapperConfiguration { static final Set TRANSLATE_VALUE_SUPPORTED_JAVA_TYPES = Set.of( String.class, Number.class, Long.class, Short.class, Integer.class, Double.class, Float.class, - Boolean.class, Character.class); + Boolean.class, Character.class, PluginConfigVariable.class); @Bean(name = "extensionPluginConfigObjectMapper") ObjectMapper extensionPluginConfigObjectMapper() { diff --git a/data-prepper-plugin-framework/src/main/java/org/opensearch/dataprepper/plugin/VariableExpander.java b/data-prepper-plugin-framework/src/main/java/org/opensearch/dataprepper/plugin/VariableExpander.java index 5cbb5136e6..7b249f0389 100644 --- a/data-prepper-plugin-framework/src/main/java/org/opensearch/dataprepper/plugin/VariableExpander.java +++ b/data-prepper-plugin-framework/src/main/java/org/opensearch/dataprepper/plugin/VariableExpander.java @@ -9,6 +9,7 @@ import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.databind.ObjectMapper; import org.opensearch.dataprepper.model.plugin.PluginConfigValueTranslator; +import org.opensearch.dataprepper.model.plugin.PluginConfigVariable; import javax.inject.Inject; import javax.inject.Named; @@ -29,8 +30,7 @@ public class VariableExpander { @Inject public VariableExpander( - @Named("extensionPluginConfigObjectMapper") - final ObjectMapper objectMapper, + @Named("extensionPluginConfigObjectMapper") final ObjectMapper objectMapper, final Set pluginConfigValueTranslators) { this.objectMapper = objectMapper; patternPluginConfigValueTranslatorMap = pluginConfigValueTranslators.stream().collect(Collectors.toMap( @@ -48,8 +48,13 @@ public T translate(final JsonParser jsonParser, final Class destinationTy .filter(entry -> entry.getKey().matches()) .map(entry -> { final String valueReferenceKey = entry.getKey().group(VALUE_REFERENCE_KEY); - return objectMapper.convertValue( - entry.getValue().translate(valueReferenceKey), destinationType); + if (destinationType.equals(PluginConfigVariable.class)) { + return (T) entry.getValue().translateToPluginConfigVariable(valueReferenceKey); + } else { + return objectMapper.convertValue( + entry.getValue().translate(valueReferenceKey), destinationType); + } + }) .findFirst() .orElseGet(() -> objectMapper.convertValue(rawValue, destinationType)); diff --git a/data-prepper-plugin-framework/src/test/java/org/opensearch/dataprepper/plugin/VariableExpanderTest.java b/data-prepper-plugin-framework/src/test/java/org/opensearch/dataprepper/plugin/VariableExpanderTest.java index 386b7fd826..c8d2559302 100644 --- a/data-prepper-plugin-framework/src/test/java/org/opensearch/dataprepper/plugin/VariableExpanderTest.java +++ b/data-prepper-plugin-framework/src/test/java/org/opensearch/dataprepper/plugin/VariableExpanderTest.java @@ -19,6 +19,7 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.opensearch.dataprepper.model.plugin.PluginConfigValueTranslator; +import org.opensearch.dataprepper.model.plugin.PluginConfigVariable; import java.io.IOException; import java.math.BigDecimal; @@ -30,6 +31,8 @@ import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; @@ -43,6 +46,32 @@ class VariableExpanderTest { private VariableExpander objectUnderTest; + private static Stream getNonStringTypeArguments() { + return Stream.of(Arguments.of(Boolean.class, "true", true), + Arguments.of(Short.class, "2", (short) 2), + Arguments.of(Integer.class, "10", 10), + Arguments.of(Long.class, "200", 200L), + Arguments.of(Double.class, "1.23", 1.23d), + Arguments.of(Float.class, "2.15", 2.15f), + Arguments.of(BigDecimal.class, "2.15", BigDecimal.valueOf(2.15)), + Arguments.of(Map.class, "{}", Collections.emptyMap())); + } + + private static Stream getStringTypeArguments() { + final String testRandomValue = "non-secret-prefix-" + RandomStringUtils.randomAlphabetic(5); + return Stream.of(Arguments.of(String.class, String.format("\"%s\"", testRandomValue), + testRandomValue), + Arguments.of(Duration.class, "\"PT15M\"", Duration.parse("PT15M")), + Arguments.of(Boolean.class, "\"true\"", true), + Arguments.of(Short.class, "\"2\"", (short) 2), + Arguments.of(Integer.class, "\"10\"", 10), + Arguments.of(Long.class, "\"200\"", 200L), + Arguments.of(Double.class, "\"1.23\"", 1.23d), + Arguments.of(Float.class, "\"2.15\"", 2.15f), + Arguments.of(BigDecimal.class, "\"2.15\"", BigDecimal.valueOf(2.15)), + Arguments.of(Character.class, "\"c\"", 'c')); + } + @BeforeEach void setUp() { objectUnderTest = new VariableExpander(OBJECT_MAPPER, Set.of(pluginConfigValueTranslator)); @@ -107,29 +136,53 @@ void testTranslateJsonParserWithStringValue_translate_success( assertThat(actualResult, equalTo(expectedResult)); } - private static Stream getNonStringTypeArguments() { - return Stream.of(Arguments.of(Boolean.class, "true", true), - Arguments.of(Short.class, "2", (short) 2), - Arguments.of(Integer.class, "10", 10), - Arguments.of(Long.class, "200", 200L), - Arguments.of(Double.class, "1.23", 1.23d), - Arguments.of(Float.class, "2.15", 2.15f), - Arguments.of(BigDecimal.class, "2.15", BigDecimal.valueOf(2.15)), - Arguments.of(Map.class, "{}", Collections.emptyMap())); + @Test + void testTranslateJsonParserWithSPluginConfigVariableValue_translate_success() throws IOException { + final String testSecretKey = "testSecretKey"; + final String testTranslatorKey = "test_prefix"; + final String testSecretReference = String.format("${{%s:%s}}", testTranslatorKey, testSecretKey); + final JsonParser jsonParser = JSON_FACTORY.createParser(String.format("\"%s\"", testSecretReference)); + jsonParser.nextToken(); + PluginConfigVariable mockPluginConfigVariable = new PluginConfigVariable() { + + String secretValue = "samplePluginConfigValue"; + + @Override + public Object getValue() { + return secretValue; + } + + @Override + public void setValue(Object updatedValue) { + this.secretValue = updatedValue.toString(); + } + + @Override + public boolean isUpdatable() { + return true; + } + }; + when(pluginConfigValueTranslator.getPrefix()).thenReturn(testTranslatorKey); + when(pluginConfigValueTranslator.translateToPluginConfigVariable(eq(testSecretKey))) + .thenReturn(mockPluginConfigVariable); + objectUnderTest = new VariableExpander(OBJECT_MAPPER, Set.of(pluginConfigValueTranslator)); + final Object actualResult = objectUnderTest.translate(jsonParser, PluginConfigVariable.class); + assertNotNull(actualResult); + assertThat(actualResult, equalTo(mockPluginConfigVariable)); } - private static Stream getStringTypeArguments() { - final String testRandomValue = "non-secret-prefix-" + RandomStringUtils.randomAlphabetic(5); - return Stream.of(Arguments.of(String.class, String.format("\"%s\"", testRandomValue), - testRandomValue), - Arguments.of(Duration.class, "\"PT15M\"", Duration.parse("PT15M")), - Arguments.of(Boolean.class, "\"true\"", true), - Arguments.of(Short.class, "\"2\"", (short) 2), - Arguments.of(Integer.class, "\"10\"", 10), - Arguments.of(Long.class, "\"200\"", 200L), - Arguments.of(Double.class, "\"1.23\"", 1.23d), - Arguments.of(Float.class, "\"2.15\"", 2.15f), - Arguments.of(BigDecimal.class, "\"2.15\"", BigDecimal.valueOf(2.15)), - Arguments.of(Character.class, "\"c\"", 'c')); + @Test + void testTranslateJsonParserWithSPluginConfigVariableValue_translate_failure() throws IOException { + final String testSecretKey = "testSecretKey"; + final String testTranslatorKey = "test_prefix"; + final String testSecretReference = String.format("${{%s:%s}}", testTranslatorKey, testSecretKey); + final JsonParser jsonParser = JSON_FACTORY.createParser(String.format("\"%s\"", testSecretReference)); + jsonParser.nextToken(); + when(pluginConfigValueTranslator.getPrefix()).thenReturn(testTranslatorKey); + when(pluginConfigValueTranslator.translateToPluginConfigVariable(eq(testSecretKey))) + .thenThrow(IllegalArgumentException.class); + objectUnderTest = new VariableExpander(OBJECT_MAPPER, Set.of(pluginConfigValueTranslator)); + assertThrows(IllegalArgumentException.class, + () -> objectUnderTest.translate(jsonParser, PluginConfigVariable.class)); } } \ No newline at end of file diff --git a/data-prepper-plugins/aws-plugin/build.gradle b/data-prepper-plugins/aws-plugin/build.gradle index 6915278023..88015e537b 100644 --- a/data-prepper-plugins/aws-plugin/build.gradle +++ b/data-prepper-plugins/aws-plugin/build.gradle @@ -1,4 +1,3 @@ - dependencies { implementation project(':data-prepper-api') implementation project(':data-prepper-plugins:aws-plugin-api') @@ -11,6 +10,7 @@ dependencies { implementation 'org.hibernate.validator:hibernate-validator:8.0.2.Final' testImplementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml' testImplementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310' + testImplementation project(':data-prepper-test-common') } test { diff --git a/data-prepper-plugins/aws-plugin/src/main/java/org/opensearch/dataprepper/plugins/aws/AwsPluginConfigVariable.java b/data-prepper-plugins/aws-plugin/src/main/java/org/opensearch/dataprepper/plugins/aws/AwsPluginConfigVariable.java new file mode 100644 index 0000000000..d53528443e --- /dev/null +++ b/data-prepper-plugins/aws-plugin/src/main/java/org/opensearch/dataprepper/plugins/aws/AwsPluginConfigVariable.java @@ -0,0 +1,54 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + */ +package org.opensearch.dataprepper.plugins.aws; + +import org.opensearch.dataprepper.model.plugin.FailedToUpdatePluginConfigValueException; +import org.opensearch.dataprepper.model.plugin.PluginConfigVariable; + +/** + * AWS Plugin configuration variable implementation. + */ +public class AwsPluginConfigVariable implements PluginConfigVariable { + + private final SecretsSupplier secretsSupplier; + private final String secretId; + private final String secretKey; + private final boolean isUpdatable; + private Object secretValue; + + public AwsPluginConfigVariable(final SecretsSupplier secretsSupplier, + final String secretId, final String secretKey, Object secretValue) { + this.secretsSupplier = secretsSupplier; + this.secretId = secretId; + this.secretKey = secretKey; + this.secretValue = secretValue; + this.isUpdatable = true; + } + + @Override + public Object getValue() { + return secretValue; + } + + @Override + public void setValue(Object newValue) { + if (!isUpdatable()) { + throw new FailedToUpdatePluginConfigValueException( + String.format("Trying to update a secrets that is not updatable. SecretId: %s SecretKey: %s", this.secretId, this.secretKey)); + } + this.secretsSupplier.updateValue(secretId, secretKey, newValue); + this.secretValue = newValue; + } + + @Override + public boolean isUpdatable() { + return isUpdatable; + } +} diff --git a/data-prepper-plugins/aws-plugin/src/main/java/org/opensearch/dataprepper/plugins/aws/AwsSecretManagerConfiguration.java b/data-prepper-plugins/aws-plugin/src/main/java/org/opensearch/dataprepper/plugins/aws/AwsSecretManagerConfiguration.java index 1aebb13a51..be95953be6 100644 --- a/data-prepper-plugins/aws-plugin/src/main/java/org/opensearch/dataprepper/plugins/aws/AwsSecretManagerConfiguration.java +++ b/data-prepper-plugins/aws-plugin/src/main/java/org/opensearch/dataprepper/plugins/aws/AwsSecretManagerConfiguration.java @@ -15,6 +15,7 @@ import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient; import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueRequest; +import software.amazon.awssdk.services.secretsmanager.model.PutSecretValueRequest; import software.amazon.awssdk.services.sts.StsClient; import software.amazon.awssdk.services.sts.auth.StsAssumeRoleCredentialsProvider; import software.amazon.awssdk.services.sts.model.AssumeRoleRequest; @@ -78,6 +79,13 @@ public GetSecretValueRequest createGetSecretValueRequest() { .build(); } + public PutSecretValueRequest putSecretValueRequest(String secretKeyValueMapAsString) { + return PutSecretValueRequest.builder() + .secretId(awsSecretId) + .secretString(secretKeyValueMapAsString) + .build(); + } + private AwsCredentialsProvider authenticateAwsConfiguration() { final AwsCredentialsProvider awsCredentialsProvider; diff --git a/data-prepper-plugins/aws-plugin/src/main/java/org/opensearch/dataprepper/plugins/aws/AwsSecretsPluginConfigValueTranslator.java b/data-prepper-plugins/aws-plugin/src/main/java/org/opensearch/dataprepper/plugins/aws/AwsSecretsPluginConfigValueTranslator.java index ba544fdb32..adeb498bfb 100644 --- a/data-prepper-plugins/aws-plugin/src/main/java/org/opensearch/dataprepper/plugins/aws/AwsSecretsPluginConfigValueTranslator.java +++ b/data-prepper-plugins/aws-plugin/src/main/java/org/opensearch/dataprepper/plugins/aws/AwsSecretsPluginConfigValueTranslator.java @@ -6,6 +6,7 @@ package org.opensearch.dataprepper.plugins.aws; import org.opensearch.dataprepper.model.plugin.PluginConfigValueTranslator; +import org.opensearch.dataprepper.model.plugin.PluginConfigVariable; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -43,4 +44,19 @@ public Object translate(final String value) { public String getPrefix() { return AWS_SECRETS_PREFIX; } + + @Override + public PluginConfigVariable translateToPluginConfigVariable(String value) { + final Matcher matcher = SECRETS_REF_PATTERN.matcher(value); + if (!matcher.matches()) { + throw new IllegalArgumentException(String.format( + "Unable to parse %s or %s according to pattern %s", + SECRET_CONFIGURATION_ID_GROUP, SECRET_KEY_GROUP, SECRETS_REF_PATTERN.pattern())); + } + final String secretId = matcher.group(SECRET_CONFIGURATION_ID_GROUP); + final String secretKey = matcher.group(SECRET_KEY_GROUP); + final Object secretValue = secretKey != null ? secretsSupplier.retrieveValue(secretId, secretKey) : + secretsSupplier.retrieveValue(secretId); + return new AwsPluginConfigVariable(secretsSupplier, secretId, secretKey, secretValue); + } } diff --git a/data-prepper-plugins/aws-plugin/src/main/java/org/opensearch/dataprepper/plugins/aws/AwsSecretsSupplier.java b/data-prepper-plugins/aws-plugin/src/main/java/org/opensearch/dataprepper/plugins/aws/AwsSecretsSupplier.java index 84fe975836..8161893d29 100644 --- a/data-prepper-plugins/aws-plugin/src/main/java/org/opensearch/dataprepper/plugins/aws/AwsSecretsSupplier.java +++ b/data-prepper-plugins/aws-plugin/src/main/java/org/opensearch/dataprepper/plugins/aws/AwsSecretsSupplier.java @@ -1,6 +1,12 @@ /* * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 + * + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * */ package org.opensearch.dataprepper.plugins.aws; @@ -8,21 +14,23 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import org.opensearch.dataprepper.model.plugin.FailedToUpdatePluginConfigValueException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient; import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueRequest; import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueResponse; +import software.amazon.awssdk.services.secretsmanager.model.PutSecretValueRequest; +import software.amazon.awssdk.services.secretsmanager.model.PutSecretValueResponse; import java.util.Map; import java.util.concurrent.ConcurrentMap; import java.util.stream.Collectors; public class AwsSecretsSupplier implements SecretsSupplier { - private static final Logger LOG = LoggerFactory.getLogger(AwsSecretsSupplier.class); static final TypeReference> MAP_TYPE_REFERENCE = new TypeReference<>() { }; - + private static final Logger LOG = LoggerFactory.getLogger(AwsSecretsSupplier.class); private final SecretValueDecoder secretValueDecoder; private final ObjectMapper objectMapper; private final Map awsSecretManagerConfigurationMap; @@ -94,6 +102,7 @@ public Object retrieveValue(String secretId) { } } + @Override public void refresh(String secretConfigId) { LOG.info("Retrieving latest secrets in aws:secrets:{}.", secretConfigId); @@ -126,4 +135,43 @@ private Object retrieveSecretsFromSecretManager(final AwsSecretManagerConfigurat return secretValueDecoder.decode(getSecretValueResponse); } } + + @Override + public String updateValue(String secretId, Object newValue) { + return updateValue(secretId, null, newValue); + } + + @Override + public String updateValue(String secretId, String keyToUpdate, Object newValue) { + Object currentSecretStore = secretIdToValue.get(secretId); + if (currentSecretStore instanceof Map) { + if (keyToUpdate == null) { + throw new IllegalArgumentException( + String.format("Key to update cannot be null for a key value based secret. secretId: %s", secretId)); + } + final Map keyValuePairs = (Map) currentSecretStore; + keyValuePairs.put(keyToUpdate, newValue); + } else { + //This store is not a key value pair store. It is just a value store. + //If we are here, either KeyToUpdate passed is null or we simply ignore it and just put value in the store + secretIdToValue.put(secretId, newValue); + } + // assuming all the secrets are string based (not binary) + String secretKeyValueMapAsString = (String) retrieveValue(secretId); + AwsSecretManagerConfiguration awsSecretManagerConfiguration = awsSecretManagerConfigurationMap.get(secretId); + PutSecretValueRequest putSecretValueRequest = + awsSecretManagerConfiguration.putSecretValueRequest(secretKeyValueMapAsString); + SecretsManagerClient secretsManagerClient = secretsManagerClientMap.get(secretId); + + try { + final PutSecretValueResponse putSecretValueResponse = secretsManagerClient.putSecretValue(putSecretValueRequest); + LOG.info("Updated key: {} in the secret {}. New version of the store is {}", + keyToUpdate, secretId, putSecretValueResponse.versionId()); + return putSecretValueResponse.versionId(); + } catch (Exception e) { + throw new FailedToUpdatePluginConfigValueException( + String.format("Failed to update the secret: %s to put a new value for the key: %s", + awsSecretManagerConfiguration.getAwsSecretId(), keyToUpdate), e); + } + } } diff --git a/data-prepper-plugins/aws-plugin/src/main/java/org/opensearch/dataprepper/plugins/aws/SecretsSupplier.java b/data-prepper-plugins/aws-plugin/src/main/java/org/opensearch/dataprepper/plugins/aws/SecretsSupplier.java index fad423f7cc..482e9323a0 100644 --- a/data-prepper-plugins/aws-plugin/src/main/java/org/opensearch/dataprepper/plugins/aws/SecretsSupplier.java +++ b/data-prepper-plugins/aws-plugin/src/main/java/org/opensearch/dataprepper/plugins/aws/SecretsSupplier.java @@ -11,4 +11,25 @@ public interface SecretsSupplier { Object retrieveValue(String secretId); void refresh(String secretId); + + /** + * Update the value of a secret key in the secret store and responds + * with the version id of the secret after the update. + * + * @param secretId The id of the secret to be updated + * @param keyToUpdate The key of the secret to be updated + * @param newValueToSet The value of the secret to be updated + * @return The version id of the secret after the update + */ + String updateValue(String secretId, String keyToUpdate, Object newValueToSet); + + /** + * Update the value of secret store (which is not a key value secret store) and responds + * with the version id of the secret after the update. + * + * @param secretId The id of the secret to be updated + * @param newValueToSet The value of the secret to be updated + * @return The version id of the secret after the update + */ + String updateValue(String secretId, Object newValueToSet); } diff --git a/data-prepper-plugins/aws-plugin/src/test/java/org/opensearch/dataprepper/plugins/aws/AwsPluginConfigVariableTest.java b/data-prepper-plugins/aws-plugin/src/test/java/org/opensearch/dataprepper/plugins/aws/AwsPluginConfigVariableTest.java new file mode 100644 index 0000000000..faad9f72d7 --- /dev/null +++ b/data-prepper-plugins/aws-plugin/src/test/java/org/opensearch/dataprepper/plugins/aws/AwsPluginConfigVariableTest.java @@ -0,0 +1,84 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + */ + +package org.opensearch.dataprepper.plugins.aws; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.opensearch.dataprepper.model.plugin.FailedToUpdatePluginConfigValueException; +import org.opensearch.dataprepper.test.helper.ReflectivelySetField; + +import java.util.UUID; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class AwsPluginConfigVariableTest { + private final String secretId = "valid@secret-manager_name"; + private final String secretKey = UUID.randomUUID().toString(); + private final Object secretValue = UUID.randomUUID().toString(); + @Mock + private SecretsSupplier secretsSupplier; + private AwsPluginConfigVariable objectUnderTest; + + @BeforeEach + void setUp() { + objectUnderTest = new AwsPluginConfigVariable( + secretsSupplier, + secretId, secretKey, + secretValue + ); + } + + @Test + void testGetPrefix() { + assertThat(objectUnderTest.getValue(), equalTo(secretValue)); + } + + @Test + void testSetValueFailure_when_secret_is_not_updatable() throws NoSuchFieldException, IllegalAccessException { + objectUnderTest = new AwsPluginConfigVariable( + secretsSupplier, + secretId, secretKey, + secretValue + ); + ReflectivelySetField.setField(AwsPluginConfigVariable.class, objectUnderTest, "isUpdatable", false); + assertThrows(FailedToUpdatePluginConfigValueException.class, () -> objectUnderTest.setValue("new-secret-to-set")); + } + + @ParameterizedTest + @ValueSource(strings = { + "", + "new-secret-to-set" + }) + void testSetValueFailure(final String input) { + when(secretsSupplier.updateValue(secretId, secretKey, input)).thenThrow(RuntimeException.class); + assertThrows(RuntimeException.class, () -> objectUnderTest.setValue(input)); + } + + @ParameterizedTest + @ValueSource(strings = { + "", + "new-secret-to-set" + }) + void testSetValueSuccess(final String input) { + objectUnderTest.setValue(input); + assertThat(objectUnderTest.getValue(), equalTo(input)); + } + +} \ No newline at end of file diff --git a/data-prepper-plugins/aws-plugin/src/test/java/org/opensearch/dataprepper/plugins/aws/AwsSecretManagerConfigurationTest.java b/data-prepper-plugins/aws-plugin/src/test/java/org/opensearch/dataprepper/plugins/aws/AwsSecretManagerConfigurationTest.java index 38c9159fc4..dd6f045a6e 100644 --- a/data-prepper-plugins/aws-plugin/src/test/java/org/opensearch/dataprepper/plugins/aws/AwsSecretManagerConfigurationTest.java +++ b/data-prepper-plugins/aws-plugin/src/test/java/org/opensearch/dataprepper/plugins/aws/AwsSecretManagerConfigurationTest.java @@ -1,6 +1,12 @@ /* * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 + * + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * */ package org.opensearch.dataprepper.plugins.aws; @@ -28,6 +34,7 @@ import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient; import software.amazon.awssdk.services.secretsmanager.SecretsManagerClientBuilder; import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueRequest; +import software.amazon.awssdk.services.secretsmanager.model.PutSecretValueRequest; import software.amazon.awssdk.services.sts.auth.StsAssumeRoleCredentialsProvider; import java.io.IOException; @@ -59,9 +66,15 @@ class AwsSecretManagerConfigurationTest { @Mock private GetSecretValueRequest.Builder getSecretValueRequestBuilder; + @Mock + private PutSecretValueRequest.Builder putSecretValueRequestBuilder; + @Mock private GetSecretValueRequest getSecretValueRequest; + @Mock + private PutSecretValueRequest putSecretValueRequest; + @Mock private SecretsManagerClientBuilder secretsManagerClientBuilder; @@ -131,6 +144,27 @@ void testCreateGetSecretValueRequest() throws IOException { verify(getSecretValueRequestBuilder).secretId("test-secret"); } + + @ParameterizedTest + @ValueSource(strings = {"", " ", "secretValue", "{\"keyToUpdate\", \"newValue\"}"}) + void testPutSecretValueRequest_construct_put_request(String secretValueToStore) throws IOException { + when(putSecretValueRequestBuilder.secretId(anyString())).thenReturn(putSecretValueRequestBuilder); + when(putSecretValueRequestBuilder.secretString(anyString())).thenReturn(putSecretValueRequestBuilder); + when(putSecretValueRequestBuilder.build()).thenReturn(putSecretValueRequest); + final InputStream inputStream = AwsSecretPluginConfigTest.class.getResourceAsStream( + "/test-aws-secret-manager-configuration-default.yaml"); + final AwsSecretManagerConfiguration awsSecretManagerConfiguration = objectMapper.readValue( + inputStream, AwsSecretManagerConfiguration.class); + try (final MockedStatic putSecretValueRequestMockedStatic = + mockStatic(PutSecretValueRequest.class)) { + putSecretValueRequestMockedStatic.when(PutSecretValueRequest::builder).thenReturn( + putSecretValueRequestBuilder); + assertThat(awsSecretManagerConfiguration.putSecretValueRequest(secretValueToStore), + is(putSecretValueRequest)); + } + verify(putSecretValueRequestBuilder).secretId("test-secret"); + } + @Test void testCreateSecretManagerClientWithDefaultCredential() throws IOException { final InputStream inputStream = AwsSecretPluginConfigTest.class.getResourceAsStream( diff --git a/data-prepper-plugins/aws-plugin/src/test/java/org/opensearch/dataprepper/plugins/aws/AwsSecretsPluginConfigValueTranslatorTest.java b/data-prepper-plugins/aws-plugin/src/test/java/org/opensearch/dataprepper/plugins/aws/AwsSecretsPluginConfigValueTranslatorTest.java index 8445c34450..e21a47fcdf 100644 --- a/data-prepper-plugins/aws-plugin/src/test/java/org/opensearch/dataprepper/plugins/aws/AwsSecretsPluginConfigValueTranslatorTest.java +++ b/data-prepper-plugins/aws-plugin/src/test/java/org/opensearch/dataprepper/plugins/aws/AwsSecretsPluginConfigValueTranslatorTest.java @@ -12,6 +12,7 @@ import org.junit.jupiter.params.provider.ValueSource; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.opensearch.dataprepper.model.plugin.PluginConfigVariable; import java.util.UUID; @@ -65,4 +66,33 @@ void testTranslateSecretIdWithoutKeyMatch() { when(secretsSupplier.retrieveValue(eq(testSecretName))).thenReturn(testSecretValue); assertThat(objectUnderTest.translate(testSecretName), equalTo(testSecretValue)); } + + @Test + void testTranslateToPluginConfigVariableWithoutKeyMatch() { + final String testSecretName = "valid@secret-manager_name"; + final String testSecretValue = UUID.randomUUID().toString(); + when(secretsSupplier.retrieveValue(eq(testSecretName))).thenReturn(testSecretValue); + PluginConfigVariable pluginConfigVariable = objectUnderTest.translateToPluginConfigVariable(testSecretName); + assertThat(pluginConfigVariable.getValue(), equalTo(testSecretValue)); + } + + @Test + void testTranslateToPluginConfigVariableWithKeyMatch() { + final String testSecretName = "valid@secret-manager_name"; + final String testSecretKey = UUID.randomUUID().toString(); + final String testSecretValue = UUID.randomUUID().toString(); + final String input = String.format("%s:%s", testSecretName, testSecretKey); + when(secretsSupplier.retrieveValue(eq(testSecretName), eq(testSecretKey))).thenReturn(testSecretValue); + PluginConfigVariable pluginConfigVariable = objectUnderTest.translateToPluginConfigVariable(input); + assertThat(pluginConfigVariable.getValue(), equalTo(testSecretValue)); + } + + @ParameterizedTest + @ValueSource(strings = { + "", + "invalid secret id with space:secret_key" + }) + void testTranslateToPluginConfigVariableInputNoMatch(final String input) { + assertThrows(IllegalArgumentException.class, () -> objectUnderTest.translateToPluginConfigVariable(input)); + } } \ No newline at end of file diff --git a/data-prepper-plugins/aws-plugin/src/test/java/org/opensearch/dataprepper/plugins/aws/AwsSecretsSupplierTest.java b/data-prepper-plugins/aws-plugin/src/test/java/org/opensearch/dataprepper/plugins/aws/AwsSecretsSupplierTest.java index 63735d3491..8fc8a07d33 100644 --- a/data-prepper-plugins/aws-plugin/src/test/java/org/opensearch/dataprepper/plugins/aws/AwsSecretsSupplierTest.java +++ b/data-prepper-plugins/aws-plugin/src/test/java/org/opensearch/dataprepper/plugins/aws/AwsSecretsSupplierTest.java @@ -1,6 +1,12 @@ /* * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 + * + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * */ package org.opensearch.dataprepper.plugins.aws; @@ -18,6 +24,8 @@ import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient; import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueRequest; import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueResponse; +import software.amazon.awssdk.services.secretsmanager.model.PutSecretValueRequest; +import software.amazon.awssdk.services.secretsmanager.model.PutSecretValueResponse; import software.amazon.awssdk.services.secretsmanager.model.SecretsManagerException; import java.util.Map; @@ -25,7 +33,9 @@ import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -53,9 +63,15 @@ class AwsSecretsSupplierTest { @Mock private GetSecretValueRequest getSecretValueRequest; + @Mock + private PutSecretValueRequest putSecretValueRequest; + @Mock private GetSecretValueResponse getSecretValueResponse; + @Mock + private PutSecretValueResponse putSecretValueResponse; + @Mock private SecretsManagerException secretsManagerException; @@ -163,4 +179,55 @@ void testRefreshSecretsWithoutKey() { objectUnderTest.refresh(TEST_AWS_SECRET_CONFIGURATION_NAME); assertThat(objectUnderTest.retrieveValue(TEST_AWS_SECRET_CONFIGURATION_NAME), equalTo(newTestValue)); } + + @ParameterizedTest + @ValueSource(strings = {"", " ", "newValue", "{\"key\":\"oldValue\"}", "{\"a\":\"b\"}"}) + void testUpdateValue_successfully_updated(String valueToSet) { + when(awsSecretManagerConfiguration.putSecretValueRequest(any())).thenReturn(putSecretValueRequest); + when(secretsManagerClient.putSecretValue(eq(putSecretValueRequest))).thenReturn(putSecretValueResponse); + String newVersionId = UUID.randomUUID().toString(); + when(putSecretValueResponse.versionId()).thenReturn(newVersionId); + objectUnderTest = new AwsSecretsSupplier(secretValueDecoder, awsSecretPluginConfig, OBJECT_MAPPER); + assertThat(objectUnderTest.updateValue(TEST_AWS_SECRET_CONFIGURATION_NAME, "key", valueToSet), + equalTo(newVersionId)); + } + + @Test + void testUpdateValue_null_key_throws_exception() { + when(secretsManagerClient.getSecretValue(eq(getSecretValueRequest))).thenReturn(getSecretValueResponse); + objectUnderTest = new AwsSecretsSupplier(secretValueDecoder, awsSecretPluginConfig, OBJECT_MAPPER); + assertThrows(IllegalArgumentException.class, + () -> objectUnderTest.updateValue(TEST_AWS_SECRET_CONFIGURATION_NAME, "newValue")); + } + + @ParameterizedTest + @ValueSource(strings = {"", " ", "newValue"}) + void testUpdateValue_null_key_doesnot_throws_exception_when_value_is_not_key_value_pair(String secretValueToSet) { + when(awsSecretManagerConfiguration.createGetSecretValueRequest()).thenReturn(getSecretValueRequest); + when(awsSecretPluginConfig.getAwsSecretManagerConfigurationMap()).thenReturn( + Map.of(TEST_AWS_SECRET_CONFIGURATION_NAME, awsSecretManagerConfiguration) + ); + when(awsSecretManagerConfiguration.createSecretManagerClient()).thenReturn(secretsManagerClient); + when(secretValueDecoder.decode(eq(getSecretValueResponse))).thenReturn(TEST_VALUE); + when(secretsManagerClient.getSecretValue(eq(getSecretValueRequest))).thenReturn(getSecretValueResponse); + when(awsSecretManagerConfiguration.putSecretValueRequest(any())).thenReturn(putSecretValueRequest); + when(secretsManagerClient.putSecretValue(eq(putSecretValueRequest))).thenReturn(putSecretValueResponse); + String versionId = UUID.randomUUID().toString(); + when(putSecretValueResponse.versionId()).thenReturn(versionId); + objectUnderTest = new AwsSecretsSupplier(secretValueDecoder, awsSecretPluginConfig, OBJECT_MAPPER); + String newValue = objectUnderTest.updateValue(TEST_AWS_SECRET_CONFIGURATION_NAME, secretValueToSet); + assertEquals(versionId, newValue); + } + + @Test + void testUpdateValue_failed_to_update() { + when(awsSecretManagerConfiguration.putSecretValueRequest(any())).thenReturn(putSecretValueRequest); + when(secretsManagerClient.putSecretValue(eq(putSecretValueRequest))).thenReturn(putSecretValueResponse); + final String testValue = "{\"key\":\"oldValue\"}"; + when(secretValueDecoder.decode(eq(getSecretValueResponse))).thenReturn(testValue); + when(putSecretValueResponse.versionId()).thenThrow(RuntimeException.class); + objectUnderTest = new AwsSecretsSupplier(secretValueDecoder, awsSecretPluginConfig, OBJECT_MAPPER); + assertThrows(RuntimeException.class, + () -> objectUnderTest.updateValue(TEST_AWS_SECRET_CONFIGURATION_NAME, "key", "newValue")); + } } \ No newline at end of file diff --git a/data-prepper-plugins/saas-source-plugins/jira-source/build.gradle b/data-prepper-plugins/saas-source-plugins/jira-source/build.gradle index 3edfc6c4f7..1cf3854ab4 100644 --- a/data-prepper-plugins/saas-source-plugins/jira-source/build.gradle +++ b/data-prepper-plugins/saas-source-plugins/jira-source/build.gradle @@ -21,6 +21,7 @@ dependencies { annotationProcessor 'org.projectlombok:lombok:1.18.30' testImplementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.13.4' + testImplementation project(path: ':data-prepper-test-common') implementation(libs.spring.context) { exclude group: 'commons-logging', module: 'commons-logging' diff --git a/data-prepper-plugins/saas-source-plugins/jira-source/src/main/java/org/opensearch/dataprepper/plugins/source/jira/configuration/Oauth2Config.java b/data-prepper-plugins/saas-source-plugins/jira-source/src/main/java/org/opensearch/dataprepper/plugins/source/jira/configuration/Oauth2Config.java index 3282e7b38f..b013bb3527 100644 --- a/data-prepper-plugins/saas-source-plugins/jira-source/src/main/java/org/opensearch/dataprepper/plugins/source/jira/configuration/Oauth2Config.java +++ b/data-prepper-plugins/saas-source-plugins/jira-source/src/main/java/org/opensearch/dataprepper/plugins/source/jira/configuration/Oauth2Config.java @@ -13,6 +13,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.AssertTrue; import lombok.Getter; +import org.opensearch.dataprepper.model.plugin.PluginConfigVariable; @Getter public class Oauth2Config { @@ -23,10 +24,10 @@ public class Oauth2Config { private String clientSecret; @JsonProperty("access_token") - private String accessToken; + private PluginConfigVariable accessToken; @JsonProperty("refresh_token") - private String refreshToken; + private PluginConfigVariable refreshToken; @AssertTrue(message = "Client ID, Client Secret, Access Token, and Refresh Token are both required for Oauth2") private boolean isOauth2ConfigValid() { diff --git a/data-prepper-plugins/saas-source-plugins/jira-source/src/main/java/org/opensearch/dataprepper/plugins/source/jira/rest/JiraRestClient.java b/data-prepper-plugins/saas-source-plugins/jira-source/src/main/java/org/opensearch/dataprepper/plugins/source/jira/rest/JiraRestClient.java index caf5d84ee7..92420ac319 100644 --- a/data-prepper-plugins/saas-source-plugins/jira-source/src/main/java/org/opensearch/dataprepper/plugins/source/jira/rest/JiraRestClient.java +++ b/data-prepper-plugins/saas-source-plugins/jira-source/src/main/java/org/opensearch/dataprepper/plugins/source/jira/rest/JiraRestClient.java @@ -110,7 +110,7 @@ public String getIssue(String issueKey) { return invokeRestApi(uri, String.class).getBody(); } - private ResponseEntity invokeRestApi(URI uri, Class responseType) throws BadRequestException{ + private ResponseEntity invokeRestApi(URI uri, Class responseType) throws BadRequestException { AddressValidation.validateInetAddress(AddressValidation.getInetAddress(uri.toString())); int retryCount = 0; while (retryCount < RETRY_ATTEMPT) { @@ -119,7 +119,7 @@ private ResponseEntity invokeRestApi(URI uri, Class responseType) thro } catch (HttpClientErrorException ex) { HttpStatus statusCode = ex.getStatusCode(); String statusMessage = ex.getMessage(); - log.error("An exception has occurred while getting response from Jira search API {}", ex.getMessage(), ex); + log.error("An exception has occurred while getting response from Jira search API {}", ex.getMessage()); if (statusCode == HttpStatus.FORBIDDEN) { throw new UnAuthorizedException(statusMessage); } else if (statusCode == HttpStatus.UNAUTHORIZED) { @@ -136,7 +136,7 @@ private ResponseEntity invokeRestApi(URI uri, Class responseType) thro } retryCount++; } - String errorMessage = String.format("Exceeded max retry attempts. Failed to execute the Rest API call %s", uri.toString()); + String errorMessage = String.format("Exceeded max retry attempts. Failed to execute the Rest API call %s", uri); log.error(errorMessage); throw new RuntimeException(errorMessage); } diff --git a/data-prepper-plugins/saas-source-plugins/jira-source/src/main/java/org/opensearch/dataprepper/plugins/source/jira/rest/auth/JiraOauthConfig.java b/data-prepper-plugins/saas-source-plugins/jira-source/src/main/java/org/opensearch/dataprepper/plugins/source/jira/rest/auth/JiraOauthConfig.java index 791c9e6ff4..aaa9850a8c 100644 --- a/data-prepper-plugins/saas-source-plugins/jira-source/src/main/java/org/opensearch/dataprepper/plugins/source/jira/rest/auth/JiraOauthConfig.java +++ b/data-prepper-plugins/saas-source-plugins/jira-source/src/main/java/org/opensearch/dataprepper/plugins/source/jira/rest/auth/JiraOauthConfig.java @@ -14,6 +14,7 @@ import org.opensearch.dataprepper.plugins.source.jira.JiraSourceConfig; import org.opensearch.dataprepper.plugins.source.jira.exception.UnAuthorizedException; import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; @@ -44,8 +45,7 @@ public class JiraOauthConfig implements JiraAuthConfig { public static final String EXPIRES_IN = "expires_in"; public static final String REFRESH_TOKEN = "refresh_token"; public static final String ACCESS_TOKEN = "access_token"; - private static final Logger log = - org.slf4j.LoggerFactory.getLogger(JiraOauthConfig.class); + private static final Logger log = LoggerFactory.getLogger(JiraOauthConfig.class); private final String clientId; private final String clientSecret; private final JiraSourceConfig jiraSourceConfig; @@ -65,8 +65,10 @@ public class JiraOauthConfig implements JiraAuthConfig { public JiraOauthConfig(JiraSourceConfig jiraSourceConfig) { this.jiraSourceConfig = jiraSourceConfig; - this.accessToken = jiraSourceConfig.getAuthenticationConfig().getOauth2Config().getAccessToken(); - this.refreshToken = jiraSourceConfig.getAuthenticationConfig().getOauth2Config().getRefreshToken(); + this.accessToken = (String) jiraSourceConfig.getAuthenticationConfig().getOauth2Config() + .getAccessToken().getValue(); + this.refreshToken = (String) jiraSourceConfig.getAuthenticationConfig() + .getOauth2Config().getRefreshToken().getValue(); this.clientId = jiraSourceConfig.getAuthenticationConfig().getOauth2Config().getClientId(); this.clientSecret = jiraSourceConfig.getAuthenticationConfig().getOauth2Config().getClientSecret(); } @@ -117,7 +119,7 @@ public void renewCredentials() { return; } - log.info("Renewing access-refresh token pair for Jira Connector."); + log.info("Renewing access token and refresh token pair for Jira Connector."); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); String payloadTemplate = "{\"grant_type\": \"%s\", \"client_id\": \"%s\", \"client_secret\": \"%s\", \"refresh_token\": \"%s\"}"; @@ -131,6 +133,12 @@ public void renewCredentials() { this.refreshToken = (String) oauthClientResponse.get(REFRESH_TOKEN); this.expiresInSeconds = (int) oauthClientResponse.get(EXPIRES_IN); this.expireTime = Instant.ofEpochMilli(System.currentTimeMillis() + (expiresInSeconds * 1000L)); + // updating config object's PluginConfigVariable so that it updates the underlying Secret store + jiraSourceConfig.getAuthenticationConfig().getOauth2Config().getAccessToken() + .setValue(this.accessToken); + jiraSourceConfig.getAuthenticationConfig().getOauth2Config().getRefreshToken() + .setValue(this.refreshToken); + log.info("Access Token and Refresh Token pair is now refreshed. Corresponding Secret store key updated."); } catch (HttpClientErrorException ex) { this.expireTime = Instant.ofEpochMilli(0); this.expiresInSeconds = 0; diff --git a/data-prepper-plugins/saas-source-plugins/jira-source/src/test/java/org/opensearch/dataprepper/plugins/source/jira/JiraConfigHelperTest.java b/data-prepper-plugins/saas-source-plugins/jira-source/src/test/java/org/opensearch/dataprepper/plugins/source/jira/JiraConfigHelperTest.java index eeb9c03941..ceadbaf65b 100644 --- a/data-prepper-plugins/saas-source-plugins/jira-source/src/test/java/org/opensearch/dataprepper/plugins/source/jira/JiraConfigHelperTest.java +++ b/data-prepper-plugins/saas-source-plugins/jira-source/src/test/java/org/opensearch/dataprepper/plugins/source/jira/JiraConfigHelperTest.java @@ -14,6 +14,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.opensearch.dataprepper.model.plugin.PluginConfigVariable; import org.opensearch.dataprepper.plugins.source.jira.configuration.AuthenticationConfig; import org.opensearch.dataprepper.plugins.source.jira.configuration.BasicConfig; import org.opensearch.dataprepper.plugins.source.jira.configuration.FilterConfig; @@ -51,10 +52,10 @@ public class JiraConfigHelperTest { IssueTypeConfig issueTypeConfig; @Mock - ProjectConfig projectConfig; + ProjectConfig projectConfig; @Mock - NameConfig nameConfig; + NameConfig nameConfig; @Mock AuthenticationConfig authenticationConfig; @@ -63,7 +64,13 @@ public class JiraConfigHelperTest { BasicConfig basicConfig; @Mock - Oauth2Config oauth2Config; + Oauth2Config oauth2Config; + + @Mock + PluginConfigVariable accessTokenPluginConfigVariable; + + @Mock + PluginConfigVariable refreshTokenPluginConfigVariable; @Test void testInitialization() { @@ -153,14 +160,14 @@ void testValidateConfigOauth2() { when(authenticationConfig.getOauth2Config()).thenReturn(oauth2Config); assertThrows(RuntimeException.class, () -> JiraConfigHelper.validateConfig(jiraSourceConfig)); - when(oauth2Config.getAccessToken()).thenReturn("id"); + when(oauth2Config.getAccessToken()).thenReturn(accessTokenPluginConfigVariable); assertThrows(RuntimeException.class, () -> JiraConfigHelper.validateConfig(jiraSourceConfig)); - when(oauth2Config.getRefreshToken()).thenReturn("credential"); + when(authenticationConfig.getOauth2Config().getRefreshToken()).thenReturn(refreshTokenPluginConfigVariable); when(oauth2Config.getAccessToken()).thenReturn(null); assertThrows(RuntimeException.class, () -> JiraConfigHelper.validateConfig(jiraSourceConfig)); - when(oauth2Config.getAccessToken()).thenReturn("id"); + when(oauth2Config.getAccessToken()).thenReturn(accessTokenPluginConfigVariable); assertDoesNotThrow(() -> JiraConfigHelper.validateConfig(jiraSourceConfig)); } } diff --git a/data-prepper-plugins/saas-source-plugins/jira-source/src/test/java/org/opensearch/dataprepper/plugins/source/jira/JiraServiceTest.java b/data-prepper-plugins/saas-source-plugins/jira-source/src/test/java/org/opensearch/dataprepper/plugins/source/jira/JiraServiceTest.java index 0de0ea47dc..484ca2caac 100644 --- a/data-prepper-plugins/saas-source-plugins/jira-source/src/test/java/org/opensearch/dataprepper/plugins/source/jira/JiraServiceTest.java +++ b/data-prepper-plugins/saas-source-plugins/jira-source/src/test/java/org/opensearch/dataprepper/plugins/source/jira/JiraServiceTest.java @@ -18,12 +18,16 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.opensearch.dataprepper.model.plugin.PluginConfigVariable; +import org.opensearch.dataprepper.plugins.source.jira.configuration.Oauth2Config; import org.opensearch.dataprepper.plugins.source.jira.exception.BadRequestException; import org.opensearch.dataprepper.plugins.source.jira.models.IssueBean; import org.opensearch.dataprepper.plugins.source.jira.models.SearchResults; import org.opensearch.dataprepper.plugins.source.jira.rest.JiraRestClient; +import org.opensearch.dataprepper.plugins.source.jira.utils.MockPluginConfigVariableImpl; import org.opensearch.dataprepper.plugins.source.source_crawler.base.PluginExecutorServiceProvider; import org.opensearch.dataprepper.plugins.source.source_crawler.model.ItemInfo; +import org.opensearch.dataprepper.test.helper.ReflectivelySetField; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -84,9 +88,19 @@ private static InputStream getResourceAsStream(String resourceName) { public static JiraSourceConfig createJiraConfigurationFromYaml(String fileName) { ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory()); try (InputStream inputStream = getResourceAsStream(fileName)) { - return objectMapper.readValue(inputStream, JiraSourceConfig.class); + JiraSourceConfig jiraSourceConfig = objectMapper.readValue(inputStream, JiraSourceConfig.class); + Oauth2Config oauth2Config = jiraSourceConfig.getAuthenticationConfig().getOauth2Config(); + if (oauth2Config != null) { + ReflectivelySetField.setField(Oauth2Config.class, oauth2Config, "accessToken", + new MockPluginConfigVariableImpl("mockAccessToken")); + ReflectivelySetField.setField(Oauth2Config.class, oauth2Config, "refreshToken", + new MockPluginConfigVariableImpl("mockRefreshToken")); + } + return jiraSourceConfig; } catch (IOException ex) { log.error("Failed to parse pipeline Yaml", ex); + } catch (Exception e) { + throw new RuntimeException(e); } return null; } @@ -95,6 +109,8 @@ public static JiraSourceConfig createJiraConfiguration(String auth_type, List issueType, List issueStatus, List projectKey) throws JsonProcessingException { + PluginConfigVariable pcvAccessToken = null; + PluginConfigVariable pcvRefreshToken = null; ObjectMapper objectMapper = new ObjectMapper(); Map authenticationMap = new HashMap<>(); Map basicMap = new HashMap<>(); @@ -103,11 +119,11 @@ public static JiraSourceConfig createJiraConfiguration(String auth_type, basicMap.put("username", "test_username"); basicMap.put("password", "test_password"); authenticationMap.put("basic", basicMap); - } else if (auth_type.equals(OAUTH2)) { + } else if (auth_type.equals(OAUTH2)) { oauth2Map.put("client_id", "test-client-id"); oauth2Map.put("client_secret", "test-client-secret"); - oauth2Map.put("access_token", "test-access-token"); - oauth2Map.put("refresh_token", "test-refresh-token"); + pcvAccessToken = new MockPluginConfigVariableImpl("test-access-token"); + pcvRefreshToken = new MockPluginConfigVariableImpl("test-refresh-token"); authenticationMap.put("oauth2", oauth2Map); } @@ -137,7 +153,18 @@ public static JiraSourceConfig createJiraConfiguration(String auth_type, jiraSourceConfigMap.put("filter", filterMap); String jiraSourceConfigJsonString = objectMapper.writeValueAsString(jiraSourceConfigMap); - return objectMapper.readValue(jiraSourceConfigJsonString, JiraSourceConfig.class); + JiraSourceConfig jiraSourceConfig = objectMapper.readValue(jiraSourceConfigJsonString, JiraSourceConfig.class); + if (jiraSourceConfig.getAuthenticationConfig().getOauth2Config() != null && pcvAccessToken != null) { + try { + ReflectivelySetField.setField(Oauth2Config.class, + jiraSourceConfig.getAuthenticationConfig().getOauth2Config(), "accessToken", pcvAccessToken); + ReflectivelySetField.setField(Oauth2Config.class, + jiraSourceConfig.getAuthenticationConfig().getOauth2Config(), "refreshToken", pcvRefreshToken); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + return jiraSourceConfig; } @AfterEach diff --git a/data-prepper-plugins/saas-source-plugins/jira-source/src/test/java/org/opensearch/dataprepper/plugins/source/jira/JiraSourceConfigTest.java b/data-prepper-plugins/saas-source-plugins/jira-source/src/test/java/org/opensearch/dataprepper/plugins/source/jira/JiraSourceConfigTest.java index 35a2450fdb..b7b30af5f6 100644 --- a/data-prepper-plugins/saas-source-plugins/jira-source/src/test/java/org/opensearch/dataprepper/plugins/source/jira/JiraSourceConfigTest.java +++ b/data-prepper-plugins/saas-source-plugins/jira-source/src/test/java/org/opensearch/dataprepper/plugins/source/jira/JiraSourceConfigTest.java @@ -10,9 +10,12 @@ package org.opensearch.dataprepper.plugins.source.jira; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.Test; +import org.opensearch.dataprepper.model.plugin.PluginConfigVariable; +import org.opensearch.dataprepper.plugins.source.jira.configuration.Oauth2Config; +import org.opensearch.dataprepper.plugins.source.jira.utils.MockPluginConfigVariableImpl; +import org.opensearch.dataprepper.test.helper.ReflectivelySetField; import java.util.ArrayList; import java.util.HashMap; @@ -27,19 +30,21 @@ import static org.opensearch.dataprepper.plugins.source.source_crawler.base.CrawlerSourceConfig.DEFAULT_NUMBER_OF_WORKERS; public class JiraSourceConfigTest { - private final String accessToken = "access token test"; - private final String refreshToken = "refresh token test"; + private final PluginConfigVariable accessToken = new MockPluginConfigVariableImpl("access token test"); + private final PluginConfigVariable refreshToken = new MockPluginConfigVariableImpl("refresh token test"); private final String clientId = "client id test"; private final String clientSecret = "client secret test"; private final String password = "test Jira Credential"; private final String username = "test Jira Id"; private final String accountUrl = "https://example.atlassian.net"; - private List projectList = new ArrayList<>(); - private List issueTypeList = new ArrayList<>(); - private List statusList = new ArrayList<>(); + private final List projectList = new ArrayList<>(); + private final List issueTypeList = new ArrayList<>(); + private final List statusList = new ArrayList<>(); private JiraSourceConfig jiraSourceConfig; - private JiraSourceConfig createJiraSourceConfig(String authtype, boolean hasToken) throws JsonProcessingException { + private JiraSourceConfig createJiraSourceConfig(String authtype, boolean hasToken) throws Exception { + PluginConfigVariable pcvAccessToken = null; + PluginConfigVariable pcvRefreshToken = null; Map configMap = new HashMap<>(); List hosts = new ArrayList<>(); hosts.add(accountUrl); @@ -48,17 +53,16 @@ private JiraSourceConfig createJiraSourceConfig(String authtype, boolean hasToke Map authenticationMap = new HashMap<>(); Map basicMap = new HashMap<>(); - Map oauth2Map = new HashMap<>(); + Map oauth2Map = new HashMap<>(); if (authtype.equals(BASIC)) { basicMap.put("username", username); basicMap.put("password", password); authenticationMap.put("basic", basicMap); } else if (authtype.equals(OAUTH2)) { if (hasToken) { - oauth2Map.put("access_token", accessToken); - oauth2Map.put("refresh_token", refreshToken); + pcvRefreshToken = refreshToken; + pcvAccessToken = accessToken; } else { - oauth2Map.put("access_token", null); oauth2Map.put("refresh_token", null); } oauth2Map.put("client_id", clientId); @@ -98,11 +102,17 @@ private JiraSourceConfig createJiraSourceConfig(String authtype, boolean hasToke ObjectMapper objectMapper = new ObjectMapper(); String jsonConfig = objectMapper.writeValueAsString(configMap); JiraSourceConfig config = objectMapper.readValue(jsonConfig, JiraSourceConfig.class); + if (config.getAuthenticationConfig().getOauth2Config() != null && pcvAccessToken != null) { + ReflectivelySetField.setField(Oauth2Config.class, + config.getAuthenticationConfig().getOauth2Config(), "accessToken", pcvAccessToken); + ReflectivelySetField.setField(Oauth2Config.class, + config.getAuthenticationConfig().getOauth2Config(), "refreshToken", pcvRefreshToken); + } return config; } @Test - void testGetters() throws JsonProcessingException { + void testGetters() throws Exception { jiraSourceConfig = createJiraSourceConfig(BASIC, false); assertEquals(jiraSourceConfig.getFilterConfig().getIssueTypeConfig().getInclude(), issueTypeList); assertEquals(jiraSourceConfig.getNumWorkers(), DEFAULT_NUMBER_OF_WORKERS); @@ -115,18 +125,17 @@ void testGetters() throws JsonProcessingException { } @Test - void testFetchGivenOauthAttributeWrongAuthType() throws JsonProcessingException { + void testFetchGivenOauthAttributeWrongAuthType() throws Exception { jiraSourceConfig = createJiraSourceConfig(BASIC, true); assertThrows(RuntimeException.class, () -> jiraSourceConfig.getAuthenticationConfig().getOauth2Config().getAccessToken()); } @Test - void testFetchGivenOauthAtrribute() throws JsonProcessingException { + void testFetchGivenOauthAtrribute() throws Exception { jiraSourceConfig = createJiraSourceConfig(OAUTH2, true); assertEquals(accessToken, jiraSourceConfig.getAuthenticationConfig().getOauth2Config().getAccessToken()); assertEquals(refreshToken, jiraSourceConfig.getAuthenticationConfig().getOauth2Config().getRefreshToken()); assertEquals(clientId, jiraSourceConfig.getAuthenticationConfig().getOauth2Config().getClientId()); assertEquals(clientSecret, jiraSourceConfig.getAuthenticationConfig().getOauth2Config().getClientSecret()); } - } diff --git a/data-prepper-plugins/saas-source-plugins/jira-source/src/test/java/org/opensearch/dataprepper/plugins/source/jira/rest/CustomRestTemplateConfigTest.java b/data-prepper-plugins/saas-source-plugins/jira-source/src/test/java/org/opensearch/dataprepper/plugins/source/jira/rest/CustomRestTemplateConfigTest.java index 11d29c78c0..1f620c822a 100644 --- a/data-prepper-plugins/saas-source-plugins/jira-source/src/test/java/org/opensearch/dataprepper/plugins/source/jira/rest/CustomRestTemplateConfigTest.java +++ b/data-prepper-plugins/saas-source-plugins/jira-source/src/test/java/org/opensearch/dataprepper/plugins/source/jira/rest/CustomRestTemplateConfigTest.java @@ -17,6 +17,7 @@ import org.junit.jupiter.params.provider.MethodSource; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.opensearch.dataprepper.model.plugin.PluginConfigVariable; import org.opensearch.dataprepper.plugins.source.jira.JiraSourceConfig; import org.opensearch.dataprepper.plugins.source.jira.configuration.AuthenticationConfig; import org.opensearch.dataprepper.plugins.source.jira.configuration.BasicConfig; @@ -49,11 +50,17 @@ class CustomRestTemplateConfigTest { private JiraAuthConfig mockAuthConfig; @Mock - private BasicConfig mockBasicConfig; + private BasicConfig mockBasicConfig; @Mock private Oauth2Config mockOauth2Config; + @Mock + private PluginConfigVariable accessTokenPluginConfigVariable; + + @Mock + private PluginConfigVariable refreshTokenPluginConfigVariable; + @Mock private AuthenticationConfig mockAuthenticationConfig; @@ -77,8 +84,9 @@ void testBasicAuthRestTemplateWithOAuth2(String authType, Class interceptorClass when(mockSourceConfig.getAuthType()).thenReturn(authType); lenient().when(mockSourceConfig.getAuthenticationConfig()).thenReturn(mockAuthenticationConfig); lenient().when(mockAuthenticationConfig.getOauth2Config()).thenReturn(mockOauth2Config); - lenient().when(mockOauth2Config.getAccessToken()).thenReturn("accessToken"); - lenient().when(mockOauth2Config.getRefreshToken()).thenReturn("refreshToken"); + lenient().when(mockOauth2Config.getAccessToken()).thenReturn(accessTokenPluginConfigVariable); + lenient().when(mockOauth2Config.getRefreshToken()).thenReturn(refreshTokenPluginConfigVariable); + lenient().when(accessTokenPluginConfigVariable.getValue()).thenReturn("accessToken"); lenient().when(mockOauth2Config.getClientId()).thenReturn("clientId"); lenient().when(mockOauth2Config.getClientSecret()).thenReturn("clientSecret"); lenient().when(mockAuthenticationConfig.getBasicConfig()).thenReturn(mockBasicConfig); diff --git a/data-prepper-plugins/saas-source-plugins/jira-source/src/test/java/org/opensearch/dataprepper/plugins/source/jira/rest/auth/JiraAuthFactoryTest.java b/data-prepper-plugins/saas-source-plugins/jira-source/src/test/java/org/opensearch/dataprepper/plugins/source/jira/rest/auth/JiraAuthFactoryTest.java index 5106bd8ad1..7ae2fe588d 100644 --- a/data-prepper-plugins/saas-source-plugins/jira-source/src/test/java/org/opensearch/dataprepper/plugins/source/jira/rest/auth/JiraAuthFactoryTest.java +++ b/data-prepper-plugins/saas-source-plugins/jira-source/src/test/java/org/opensearch/dataprepper/plugins/source/jira/rest/auth/JiraAuthFactoryTest.java @@ -15,6 +15,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.opensearch.dataprepper.model.plugin.PluginConfigVariable; import org.opensearch.dataprepper.plugins.source.jira.JiraSourceConfig; import org.opensearch.dataprepper.plugins.source.jira.configuration.AuthenticationConfig; import org.opensearch.dataprepper.plugins.source.jira.configuration.Oauth2Config; @@ -31,11 +32,17 @@ public class JiraAuthFactoryTest { private JiraSourceConfig sourceConfig; @Mock - private AuthenticationConfig authenticationConfig; + private AuthenticationConfig authenticationConfig; @Mock private Oauth2Config oauth2Config; + @Mock + private PluginConfigVariable accessTokenPluginConfigVariable; + + @Mock + private PluginConfigVariable refreshTokenPluginConfigVariable; + private JiraAuthFactory jiraAuthFactory; @BeforeEach @@ -48,6 +55,9 @@ void testGetObjectOauth2() { when(sourceConfig.getAuthType()).thenReturn(OAUTH2); when(sourceConfig.getAuthenticationConfig()).thenReturn(authenticationConfig); when(authenticationConfig.getOauth2Config()).thenReturn(oauth2Config); + when(oauth2Config.getRefreshToken()).thenReturn(refreshTokenPluginConfigVariable); + when(oauth2Config.getAccessToken()).thenReturn(accessTokenPluginConfigVariable); + when(accessTokenPluginConfigVariable.getValue()).thenReturn("mockRefreshToken"); assertInstanceOf(JiraOauthConfig.class, jiraAuthFactory.getObject()); } diff --git a/data-prepper-plugins/saas-source-plugins/jira-source/src/test/java/org/opensearch/dataprepper/plugins/source/jira/utils/MockPluginConfigVariableImpl.java b/data-prepper-plugins/saas-source-plugins/jira-source/src/test/java/org/opensearch/dataprepper/plugins/source/jira/utils/MockPluginConfigVariableImpl.java new file mode 100644 index 0000000000..aa8cfd87ab --- /dev/null +++ b/data-prepper-plugins/saas-source-plugins/jira-source/src/test/java/org/opensearch/dataprepper/plugins/source/jira/utils/MockPluginConfigVariableImpl.java @@ -0,0 +1,40 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + */ + +package org.opensearch.dataprepper.plugins.source.jira.utils; + +import org.opensearch.dataprepper.model.plugin.PluginConfigVariable; + +/** + * Mock implementation of PluginConfigVariable interface used only for Unit Testing. + */ +public class MockPluginConfigVariableImpl implements PluginConfigVariable { + + private Object defaultValue; + + public MockPluginConfigVariableImpl(Object defaultValue) { + this.defaultValue = defaultValue; + } + + @Override + public Object getValue() { + return null; + } + + @Override + public void setValue(Object someValue) { + this.defaultValue = someValue; + } + + @Override + public boolean isUpdatable() { + return true; + } +} diff --git a/data-prepper-plugins/saas-source-plugins/jira-source/src/test/resources/oauth2-auth-jira-pipeline.yaml b/data-prepper-plugins/saas-source-plugins/jira-source/src/test/resources/oauth2-auth-jira-pipeline.yaml index 09c9e9f2c5..7a4afd3abf 100644 --- a/data-prepper-plugins/saas-source-plugins/jira-source/src/test/resources/oauth2-auth-jira-pipeline.yaml +++ b/data-prepper-plugins/saas-source-plugins/jira-source/src/test/resources/oauth2-auth-jira-pipeline.yaml @@ -1,8 +1,6 @@ -hosts: ["https://jira.com/"] +hosts: [ "https://jira.com/" ] authentication: oauth2: client_id: "client_id" client_secret: "client_secret" - access_token: "access_token" - refresh_token: "refresh_token"