Skip to content
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
6 changes: 6 additions & 0 deletions .changes/next-release/feature-AWSSDKforJavav2-ea2197e.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"type": "feature",
"category": "AWS SDK for Java v2",
"contributor": "",
"description": "Added support for the AWS_IGNORE_CONFIGURED_ENDPOINT_URLS setting to skip endpoint URLs from environment variables and config files."
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,12 @@ private Optional<ClientEndpoint> clientEndpointFromClientOverride(Builder builde
}

private Optional<ClientEndpoint> clientEndpointFromEnvironment(Builder builder) {
initializeProfileFileDefaults(builder);
if (shouldIgnoreConfiguredEndpointUrls(builder)) {
log.debug(() -> "Configured endpoint URLs are being ignored because ignore_configured_endpoint_urls is true.");
return Optional.empty();
}

if (builder.serviceEndpointOverrideEnvironmentVariable == null ||
builder.serviceEndpointOverrideSystemProperty == null ||
builder.serviceProfileProperty == null) {
Expand Down Expand Up @@ -181,6 +187,15 @@ private Optional<URI> servicesProperty(Builder builder) {
return createUri("services section property", serviceEndpoint);
}

private boolean shouldIgnoreConfiguredEndpointUrls(Builder builder) {
return IgnoreConfiguredEndpointUrlsProvider.builder()
.profileFile(builder.profileFile)
.profileName(builder.profileName)
.build()
.ignoreConfiguredEndpointUrls()
.orElse(false);
}

private Optional<ClientEndpoint> clientEndpointFromServiceMetadata(Builder builder) {
// This value is generally overridden after endpoints 2.0. It seems to exist for backwards-compatibility
// with older client versions or interceptors.
Expand Down Expand Up @@ -479,6 +494,7 @@ public <T> Builder putAdvancedOption(ServiceMetadataAdvancedOption<T> option, T
return this;
}


public AwsClientEndpointProvider build() {
return new AwsClientEndpointProvider(this);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

package software.amazon.awssdk.awscore.endpoint;

import java.util.Optional;
import java.util.function.Supplier;
import software.amazon.awssdk.annotations.SdkProtectedApi;
import software.amazon.awssdk.core.SdkSystemSetting;
import software.amazon.awssdk.profiles.ProfileFile;
import software.amazon.awssdk.profiles.ProfileFileSystemSetting;
import software.amazon.awssdk.profiles.ProfileProperty;
import software.amazon.awssdk.utils.Validate;

/**
* Resolves whether configured endpoint URLs should be ignored. This checks the system property, environment variable,
* and profile file for the {@code ignore_configured_endpoint_urls} setting.
*
* <p>When this returns {@code true}, the SDK will not read endpoint URLs from environment variables, system properties,
* or the shared configuration file. Programmatic endpoint overrides on the client builder are not affected.
*/
@SdkProtectedApi
public class IgnoreConfiguredEndpointUrlsProvider {
private final Supplier<ProfileFile> profileFile;
private final String profileName;

private IgnoreConfiguredEndpointUrlsProvider(Builder builder) {
this.profileFile = Validate.paramNotNull(builder.profileFile, "profileFile");
this.profileName = builder.profileName;
}

public static Builder builder() {
return new Builder();
}

/**
* Returns {@code true} when configured endpoint URLs should be ignored, {@code false} otherwise.
* Resolution order: system property, then environment variable, then profile file. If none are set, returns
* empty.
*/
public Optional<Boolean> ignoreConfiguredEndpointUrls() {
Optional<Boolean> setting = SdkSystemSetting.AWS_IGNORE_CONFIGURED_ENDPOINT_URLS.getBooleanValue();
if (setting.isPresent()) {
return setting;
}

return profileFile.get()
.profile(profileName())
.flatMap(p -> p.booleanProperty(ProfileProperty.IGNORE_CONFIGURED_ENDPOINT_URLS));
}

private String profileName() {
return profileName != null ? profileName : ProfileFileSystemSetting.AWS_PROFILE.getStringValueOrThrow();
}

public static final class Builder {
private Supplier<ProfileFile> profileFile = ProfileFile::defaultProfileFile;
private String profileName;

private Builder() {
}

public Builder profileFile(Supplier<ProfileFile> profileFile) {
this.profileFile = profileFile;
return this;
}

public Builder profileName(String profileName) {
this.profileName = profileName;
return this;
}

public IgnoreConfiguredEndpointUrlsProvider build() {
return new IgnoreConfiguredEndpointUrlsProvider(this);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

package software.amazon.awssdk.awscore.endpoint;

import static org.assertj.core.api.Assertions.assertThat;

import java.util.Optional;
import java.util.stream.Stream;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import software.amazon.awssdk.core.SdkSystemSetting;
import software.amazon.awssdk.profiles.ProfileFile;
import software.amazon.awssdk.testutils.EnvironmentVariableHelper;
import software.amazon.awssdk.utils.StringInputStream;

class IgnoreConfiguredEndpointUrlsProviderTest {
private static final EnvironmentVariableHelper ENVIRONMENT_VARIABLE_HELPER = new EnvironmentVariableHelper();
private static final String PROFILE = "test";

@BeforeEach
void setup() {
ENVIRONMENT_VARIABLE_HELPER.reset();
System.clearProperty(SdkSystemSetting.AWS_IGNORE_CONFIGURED_ENDPOINT_URLS.property());
}

@AfterEach
void teardown() {
ENVIRONMENT_VARIABLE_HELPER.reset();
System.clearProperty(SdkSystemSetting.AWS_IGNORE_CONFIGURED_ENDPOINT_URLS.property());
}

@ParameterizedTest(name = "{index} - {0}")
@MethodSource("testCases")
void resolvesCorrectly(String description, String systemProperty, String envVar, String profileValue,
Optional<Boolean> expected) {
if (systemProperty != null) {
System.setProperty(SdkSystemSetting.AWS_IGNORE_CONFIGURED_ENDPOINT_URLS.property(), systemProperty);
}
if (envVar != null) {
ENVIRONMENT_VARIABLE_HELPER.set(SdkSystemSetting.AWS_IGNORE_CONFIGURED_ENDPOINT_URLS, envVar);
}

ProfileFile profileFile = profileFile(profileValue);

IgnoreConfiguredEndpointUrlsProvider provider =
IgnoreConfiguredEndpointUrlsProvider.builder()
.profileFile(() -> profileFile)
.profileName(PROFILE)
.build();

assertThat(provider.ignoreConfiguredEndpointUrls()).isEqualTo(expected);
}

private static Stream<Arguments> testCases() {
return Stream.of(
Arguments.of("nothing set returns empty", null, null, null, Optional.empty()),
Arguments.of("system property true", "true", null, null, Optional.of(true)),
Arguments.of("system property false", "false", null, null, Optional.of(false)),
Arguments.of("system property case insensitive True", "True", null, null, Optional.of(true)),
Arguments.of("system property case insensitive TRUE", "TRUE", null, null, Optional.of(true)),
Arguments.of("env var true", null, "true", null, Optional.of(true)),
Arguments.of("env var false", null, "false", null, Optional.of(false)),
Arguments.of("profile true", null, null, "true", Optional.of(true)),
Arguments.of("profile false", null, null, "false", Optional.of(false)),
Arguments.of("system property wins over env var", "true", "false", null, Optional.of(true)),
Arguments.of("system property false wins over env var true", "false", "true", null, Optional.of(false)),
Arguments.of("system property wins over profile", "true", null, "false", Optional.of(true)),
Arguments.of("env var wins over profile", null, "true", "false", Optional.of(true)),
Arguments.of("env var false wins over profile true", null, "false", "true", Optional.of(false)),
Arguments.of("system property wins over both", "true", "false", "false", Optional.of(true)),
Arguments.of("system property false wins over both", "false", "true", "true", Optional.of(false))
);
}

private static ProfileFile profileFile(String ignoreConfiguredEndpointUrlsValue) {
StringBuilder content = new StringBuilder();
content.append("[profile test]\n");
if (ignoreConfiguredEndpointUrlsValue != null) {
content.append("ignore_configured_endpoint_urls = ").append(ignoreConfiguredEndpointUrlsValue).append("\n");
}
return ProfileFile.builder()
.type(ProfileFile.Type.CONFIGURATION)
.content(new StringInputStream(content.toString()))
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ public final class ProfileProperty {

public static final String USE_FIPS_ENDPOINT = "use_fips_endpoint";

public static final String IGNORE_CONFIGURED_ENDPOINT_URLS = "ignore_configured_endpoint_urls";

public static final String EC2_METADATA_SERVICE_ENDPOINT_MODE = "ec2_metadata_service_endpoint_mode";

public static final String EC2_METADATA_SERVICE_ENDPOINT = "ec2_metadata_service_endpoint";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,12 @@ public enum SdkSystemSetting implements SystemSetting {
*/
AWS_USE_FIPS_ENDPOINT("aws.useFipsEndpoint", null),

/**
* Defines whether endpoint URLs from environment variables, system properties, and the shared configuration file
* should be ignored. Endpoint URLs set programmatically via the client builder are not affected.
*/
AWS_IGNORE_CONFIGURED_ENDPOINT_URLS("aws.ignoreConfiguredEndpointUrls", null),

/**
* Whether request compression is disabled for operations marked with the RequestCompression trait. The default value is
* false, i.e., request compression is enabled.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider;
import software.amazon.awssdk.core.SdkSystemSetting;
import software.amazon.awssdk.profiles.ProfileFile;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.protocolrestjson.ProtocolRestJsonClient;
Expand All @@ -28,6 +29,8 @@ public class EndpointSharedConfigTest {
private static final String GLOBAL_SYS_PROP = "aws.endpointUrl";
private static final String SERVICE_ENV_VAR = "AWS_ENDPOINT_URL_AMAZONPROTOCOLRESTJSON";
private static final String SERVICE_SYS_PROP = "aws.endpointUrlProtocolRestJson";
private static final String IGNORE_ENDPOINT_URLS_SYS_PROP =
SdkSystemSetting.AWS_IGNORE_CONFIGURED_ENDPOINT_URLS.property();

@Parameterized.Parameter
public TestCase testCase;
Expand All @@ -37,6 +40,7 @@ public void resolvesCorrectEndpoint() {
Map<String, String> systemPropertiesBeforeTest = new HashMap<>();
systemPropertiesBeforeTest.put(GLOBAL_SYS_PROP, System.getProperty(GLOBAL_SYS_PROP));
systemPropertiesBeforeTest.put(SERVICE_SYS_PROP, System.getProperty(SERVICE_SYS_PROP));
systemPropertiesBeforeTest.put(IGNORE_ENDPOINT_URLS_SYS_PROP, System.getProperty(IGNORE_ENDPOINT_URLS_SYS_PROP));

EnvironmentVariableHelper helper = new EnvironmentVariableHelper();

Expand Down Expand Up @@ -66,6 +70,10 @@ public void resolvesCorrectEndpoint() {
System.setProperty(SERVICE_SYS_PROP, testCase.serviceSystemPropSetting);
}

if (testCase.ignoreConfiguredEndpointUrls) {
System.setProperty(IGNORE_ENDPOINT_URLS_SYS_PROP, "true");
}

StringBuilder profileFileContent = new StringBuilder();
profileFileContent.append("[default]\n");
if (testCase.globalProfileSetting != null) {
Expand Down Expand Up @@ -128,7 +136,8 @@ public static Iterable<TestCase> testCases() {
"Global environment variable",
"Services Section profile file",
"Service profile file",
"Global profile file");
"Global profile file",
"Ignore configured endpoint URLs");

boolean[][] settingCombinations = getSettingCombinations(settingNames.size());

Expand Down Expand Up @@ -161,6 +170,9 @@ private static TestCase createCase(List<String> settingNames,
}
}

boolean ignoreConfiguredEndpointUrls = settings[8];
expectedEndpointIndex = applyIgnoreConfiguredEndpointUrls(expectedEndpointIndex, ignoreConfiguredEndpointUrls);

// Create case name
String caseName;
if (firstTrueSetting == null) {
Expand All @@ -176,7 +188,17 @@ private static TestCase createCase(List<String> settingNames,
caseName += ".";
}

return new TestCase(settings, expectedEndpointIndex, caseName);
return new TestCase(settings, expectedEndpointIndex, ignoreConfiguredEndpointUrls, caseName);
}

/**
* When ignore_configured_endpoint_urls is true, all endpoint sources are suppressed except client override (index 0).
*/
private static Integer applyIgnoreConfiguredEndpointUrls(Integer expectedEndpointIndex, boolean ignore) {
if (!ignore || Integer.valueOf(0).equals(expectedEndpointIndex)) {
return expectedEndpointIndex;
}
return null;
}

public static void printArrayOfArrays(boolean[][] arrays) {
Expand Down Expand Up @@ -229,13 +251,15 @@ public static class TestCase {
private final String serviceProfileSetting;
private final String globalProfileSetting;
private final String serviceSectionProfileSetting;
private final boolean ignoreConfiguredEndpointUrls;
private final String caseName;
private final String expectedEndpoint;

public TestCase(boolean[] settings, Integer expectedEndpointIndex, String caseName) {
public TestCase(boolean[] settings, Integer expectedEndpointIndex, boolean ignoreConfiguredEndpointUrls,
String caseName) {
this(endpoint(settings, 0), endpoint(settings, 1), endpoint(settings, 2), endpoint(settings, 3),
endpoint(settings, 4), endpoint(settings, 5), endpoint(settings, 6), endpoint(settings, 7),
endpointForIndex(expectedEndpointIndex), caseName);
ignoreConfiguredEndpointUrls, endpointForIndex(expectedEndpointIndex), caseName);
}

private static String endpoint(boolean[] settings, int i) {
Expand All @@ -257,6 +281,7 @@ private TestCase(String clientSetting,
String serviceSectionProfileSetting,
String serviceProfileSetting,
String globalProfileSetting,
boolean ignoreConfiguredEndpointUrls,
String expectedEndpoint,
String caseName) {
this.clientSetting = clientSetting;
Expand All @@ -267,6 +292,7 @@ private TestCase(String clientSetting,
this.serviceProfileSetting = serviceProfileSetting;
this.globalProfileSetting = globalProfileSetting;
this.serviceSectionProfileSetting = serviceSectionProfileSetting;
this.ignoreConfiguredEndpointUrls = ignoreConfiguredEndpointUrls;
this.expectedEndpoint = expectedEndpoint;
this.caseName = caseName;
}
Expand Down
Loading
Loading