Add proxy username and password settings for Azure repository (#2098)
Added username/password proxy settings for Azure repository. Security settings: - azure.client.*.proxy.username - Proxy user name - azure.client.*.proxy.password - Proxy user password Signed-off-by: Andrey Pleskach <ples@aiven.io>
This commit is contained in:
parent
6b6f03368f
commit
62361ceafc
|
@ -94,13 +94,15 @@ public class AzureRepositoryPlugin extends Plugin implements RepositoryPlugin, R
|
||||||
AzureStorageSettings.ENDPOINT_SUFFIX_SETTING,
|
AzureStorageSettings.ENDPOINT_SUFFIX_SETTING,
|
||||||
AzureStorageSettings.TIMEOUT_SETTING,
|
AzureStorageSettings.TIMEOUT_SETTING,
|
||||||
AzureStorageSettings.MAX_RETRIES_SETTING,
|
AzureStorageSettings.MAX_RETRIES_SETTING,
|
||||||
AzureStorageSettings.PROXY_TYPE_SETTING,
|
|
||||||
AzureStorageSettings.PROXY_HOST_SETTING,
|
|
||||||
AzureStorageSettings.PROXY_PORT_SETTING,
|
|
||||||
AzureStorageSettings.CONNECT_TIMEOUT_SETTING,
|
AzureStorageSettings.CONNECT_TIMEOUT_SETTING,
|
||||||
AzureStorageSettings.WRITE_TIMEOUT_SETTING,
|
AzureStorageSettings.WRITE_TIMEOUT_SETTING,
|
||||||
AzureStorageSettings.READ_TIMEOUT_SETTING,
|
AzureStorageSettings.READ_TIMEOUT_SETTING,
|
||||||
AzureStorageSettings.RESPONSE_TIMEOUT_SETTING
|
AzureStorageSettings.RESPONSE_TIMEOUT_SETTING,
|
||||||
|
AzureStorageSettings.PROXY_TYPE_SETTING,
|
||||||
|
AzureStorageSettings.PROXY_HOST_SETTING,
|
||||||
|
AzureStorageSettings.PROXY_PORT_SETTING,
|
||||||
|
AzureStorageSettings.PROXY_USERNAME_SETTING,
|
||||||
|
AzureStorageSettings.PROXY_PASSWORD_SETTING
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,6 @@ import com.azure.core.http.HttpPipelinePosition;
|
||||||
import com.azure.core.http.HttpRequest;
|
import com.azure.core.http.HttpRequest;
|
||||||
import com.azure.core.http.HttpResponse;
|
import com.azure.core.http.HttpResponse;
|
||||||
import com.azure.core.http.ProxyOptions;
|
import com.azure.core.http.ProxyOptions;
|
||||||
import com.azure.core.http.ProxyOptions.Type;
|
|
||||||
import com.azure.core.http.netty.NettyAsyncHttpClientBuilder;
|
import com.azure.core.http.netty.NettyAsyncHttpClientBuilder;
|
||||||
import com.azure.core.http.policy.HttpPipelinePolicy;
|
import com.azure.core.http.policy.HttpPipelinePolicy;
|
||||||
import com.azure.core.util.Configuration;
|
import com.azure.core.util.Configuration;
|
||||||
|
@ -66,12 +65,11 @@ import org.opensearch.common.unit.ByteSizeUnit;
|
||||||
import org.opensearch.common.unit.ByteSizeValue;
|
import org.opensearch.common.unit.ByteSizeValue;
|
||||||
import org.opensearch.common.unit.TimeValue;
|
import org.opensearch.common.unit.TimeValue;
|
||||||
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.Authenticator;
|
||||||
import java.net.Proxy;
|
import java.net.PasswordAuthentication;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
@ -169,15 +167,20 @@ public class AzureStorageService implements AutoCloseable {
|
||||||
final NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup(new NioThreadFactory());
|
final NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup(new NioThreadFactory());
|
||||||
final NettyAsyncHttpClientBuilder clientBuilder = new NettyAsyncHttpClientBuilder().eventLoopGroup(eventLoopGroup);
|
final NettyAsyncHttpClientBuilder clientBuilder = new NettyAsyncHttpClientBuilder().eventLoopGroup(eventLoopGroup);
|
||||||
|
|
||||||
final Proxy proxy = azureStorageSettings.getProxy();
|
SocketAccess.doPrivilegedVoidException(() -> {
|
||||||
if (proxy != null) {
|
final ProxySettings proxySettings = azureStorageSettings.getProxySettings();
|
||||||
final Type type = Arrays.stream(Type.values())
|
if (proxySettings != ProxySettings.NO_PROXY_SETTINGS) {
|
||||||
.filter(t -> t.toProxyType().equals(proxy.type()))
|
if (proxySettings.isAuthenticated()) {
|
||||||
.findFirst()
|
Authenticator.setDefault(new Authenticator() {
|
||||||
.orElseThrow(() -> new IllegalArgumentException("Unsupported proxy type: " + proxy.type()));
|
@Override
|
||||||
|
protected PasswordAuthentication getPasswordAuthentication() {
|
||||||
clientBuilder.proxy(new ProxyOptions(type, (InetSocketAddress) proxy.address()));
|
return new PasswordAuthentication(proxySettings.getUsername(), proxySettings.getPassword().toCharArray());
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
clientBuilder.proxy(new ProxyOptions(proxySettings.getType().toProxyType(), proxySettings.getAddress()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
final TimeValue connectTimeout = azureStorageSettings.getConnectTimeout();
|
final TimeValue connectTimeout = azureStorageSettings.getConnectTimeout();
|
||||||
if (connectTimeout != null) {
|
if (connectTimeout != null) {
|
||||||
|
|
|
@ -44,8 +44,6 @@ import org.opensearch.common.settings.Settings;
|
||||||
import org.opensearch.common.settings.SettingsException;
|
import org.opensearch.common.settings.SettingsException;
|
||||||
import org.opensearch.common.unit.TimeValue;
|
import org.opensearch.common.unit.TimeValue;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.net.Proxy;
|
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -143,10 +141,10 @@ final class AzureStorageSettings {
|
||||||
);
|
);
|
||||||
|
|
||||||
/** The type of the proxy to connect to azure through. Can be direct (no proxy, default), http or socks */
|
/** The type of the proxy to connect to azure through. Can be direct (no proxy, default), http or socks */
|
||||||
public static final AffixSetting<Proxy.Type> PROXY_TYPE_SETTING = Setting.affixKeySetting(
|
public static final AffixSetting<ProxySettings.ProxyType> PROXY_TYPE_SETTING = Setting.affixKeySetting(
|
||||||
AZURE_CLIENT_PREFIX_KEY,
|
AZURE_CLIENT_PREFIX_KEY,
|
||||||
"proxy.type",
|
"proxy.type",
|
||||||
(key) -> new Setting<>(key, "direct", s -> Proxy.Type.valueOf(s.toUpperCase(Locale.ROOT)), Property.NodeScope),
|
(key) -> new Setting<>(key, "direct", s -> ProxySettings.ProxyType.valueOf(s.toUpperCase(Locale.ROOT)), Property.NodeScope),
|
||||||
() -> ACCOUNT_SETTING,
|
() -> ACCOUNT_SETTING,
|
||||||
() -> KEY_SETTING
|
() -> KEY_SETTING
|
||||||
);
|
);
|
||||||
|
@ -162,27 +160,50 @@ final class AzureStorageSettings {
|
||||||
);
|
);
|
||||||
|
|
||||||
/** The port of a proxy to connect to azure through. */
|
/** The port of a proxy to connect to azure through. */
|
||||||
public static final Setting<Integer> PROXY_PORT_SETTING = Setting.affixKeySetting(
|
public static final AffixSetting<Integer> PROXY_PORT_SETTING = Setting.affixKeySetting(
|
||||||
AZURE_CLIENT_PREFIX_KEY,
|
AZURE_CLIENT_PREFIX_KEY,
|
||||||
"proxy.port",
|
"proxy.port",
|
||||||
(key) -> Setting.intSetting(key, 0, 0, 65535, Setting.Property.NodeScope),
|
(key) -> Setting.intSetting(key, 0, 0, 65535, Setting.Property.NodeScope),
|
||||||
() -> ACCOUNT_SETTING,
|
|
||||||
() -> KEY_SETTING,
|
() -> KEY_SETTING,
|
||||||
|
() -> ACCOUNT_SETTING,
|
||||||
() -> PROXY_TYPE_SETTING,
|
() -> PROXY_TYPE_SETTING,
|
||||||
() -> PROXY_HOST_SETTING
|
() -> PROXY_HOST_SETTING
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/** The username of a proxy to connect */
|
||||||
|
static final AffixSetting<SecureString> PROXY_USERNAME_SETTING = Setting.affixKeySetting(
|
||||||
|
AZURE_CLIENT_PREFIX_KEY,
|
||||||
|
"proxy.username",
|
||||||
|
key -> SecureSetting.secureString(key, null),
|
||||||
|
() -> KEY_SETTING,
|
||||||
|
() -> ACCOUNT_SETTING,
|
||||||
|
() -> PROXY_TYPE_SETTING,
|
||||||
|
() -> PROXY_HOST_SETTING
|
||||||
|
);
|
||||||
|
|
||||||
|
/** The password of a proxy to connect */
|
||||||
|
static final AffixSetting<SecureString> PROXY_PASSWORD_SETTING = Setting.affixKeySetting(
|
||||||
|
AZURE_CLIENT_PREFIX_KEY,
|
||||||
|
"proxy.password",
|
||||||
|
key -> SecureSetting.secureString(key, null),
|
||||||
|
() -> KEY_SETTING,
|
||||||
|
() -> ACCOUNT_SETTING,
|
||||||
|
() -> PROXY_TYPE_SETTING,
|
||||||
|
() -> PROXY_HOST_SETTING,
|
||||||
|
() -> PROXY_USERNAME_SETTING
|
||||||
|
);
|
||||||
|
|
||||||
private final String account;
|
private final String account;
|
||||||
private final String connectString;
|
private final String connectString;
|
||||||
private final String endpointSuffix;
|
private final String endpointSuffix;
|
||||||
private final TimeValue timeout;
|
private final TimeValue timeout;
|
||||||
private final int maxRetries;
|
private final int maxRetries;
|
||||||
private final Proxy proxy;
|
|
||||||
private final LocationMode locationMode;
|
private final LocationMode locationMode;
|
||||||
private final TimeValue connectTimeout;
|
private final TimeValue connectTimeout;
|
||||||
private final TimeValue writeTimeout;
|
private final TimeValue writeTimeout;
|
||||||
private final TimeValue readTimeout;
|
private final TimeValue readTimeout;
|
||||||
private final TimeValue responseTimeout;
|
private final TimeValue responseTimeout;
|
||||||
|
private final ProxySettings proxySettings;
|
||||||
|
|
||||||
// copy-constructor
|
// copy-constructor
|
||||||
private AzureStorageSettings(
|
private AzureStorageSettings(
|
||||||
|
@ -191,24 +212,24 @@ final class AzureStorageSettings {
|
||||||
String endpointSuffix,
|
String endpointSuffix,
|
||||||
TimeValue timeout,
|
TimeValue timeout,
|
||||||
int maxRetries,
|
int maxRetries,
|
||||||
Proxy proxy,
|
|
||||||
LocationMode locationMode,
|
LocationMode locationMode,
|
||||||
TimeValue connectTimeout,
|
TimeValue connectTimeout,
|
||||||
TimeValue writeTimeout,
|
TimeValue writeTimeout,
|
||||||
TimeValue readTimeout,
|
TimeValue readTimeout,
|
||||||
TimeValue responseTimeout
|
TimeValue responseTimeout,
|
||||||
|
ProxySettings proxySettings
|
||||||
) {
|
) {
|
||||||
this.account = account;
|
this.account = account;
|
||||||
this.connectString = connectString;
|
this.connectString = connectString;
|
||||||
this.endpointSuffix = endpointSuffix;
|
this.endpointSuffix = endpointSuffix;
|
||||||
this.timeout = timeout;
|
this.timeout = timeout;
|
||||||
this.maxRetries = maxRetries;
|
this.maxRetries = maxRetries;
|
||||||
this.proxy = proxy;
|
|
||||||
this.locationMode = locationMode;
|
this.locationMode = locationMode;
|
||||||
this.connectTimeout = connectTimeout;
|
this.connectTimeout = connectTimeout;
|
||||||
this.writeTimeout = writeTimeout;
|
this.writeTimeout = writeTimeout;
|
||||||
this.readTimeout = readTimeout;
|
this.readTimeout = readTimeout;
|
||||||
this.responseTimeout = responseTimeout;
|
this.responseTimeout = responseTimeout;
|
||||||
|
this.proxySettings = proxySettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AzureStorageSettings(
|
private AzureStorageSettings(
|
||||||
|
@ -218,42 +239,23 @@ final class AzureStorageSettings {
|
||||||
String endpointSuffix,
|
String endpointSuffix,
|
||||||
TimeValue timeout,
|
TimeValue timeout,
|
||||||
int maxRetries,
|
int maxRetries,
|
||||||
Proxy.Type proxyType,
|
|
||||||
String proxyHost,
|
|
||||||
Integer proxyPort,
|
|
||||||
TimeValue connectTimeout,
|
TimeValue connectTimeout,
|
||||||
TimeValue writeTimeout,
|
TimeValue writeTimeout,
|
||||||
TimeValue readTimeout,
|
TimeValue readTimeout,
|
||||||
TimeValue responseTimeout
|
TimeValue responseTimeout,
|
||||||
|
ProxySettings proxySettings
|
||||||
) {
|
) {
|
||||||
this.account = account;
|
this.account = account;
|
||||||
this.connectString = buildConnectString(account, key, sasToken, endpointSuffix);
|
this.connectString = buildConnectString(account, key, sasToken, endpointSuffix);
|
||||||
this.endpointSuffix = endpointSuffix;
|
this.endpointSuffix = endpointSuffix;
|
||||||
this.timeout = timeout;
|
this.timeout = timeout;
|
||||||
this.maxRetries = maxRetries;
|
this.maxRetries = maxRetries;
|
||||||
// Register the proxy if we have any
|
|
||||||
// Validate proxy settings
|
|
||||||
if (proxyType.equals(Proxy.Type.DIRECT) && ((proxyPort != 0) || Strings.hasText(proxyHost))) {
|
|
||||||
throw new SettingsException("Azure Proxy port or host have been set but proxy type is not defined.");
|
|
||||||
}
|
|
||||||
if ((proxyType.equals(Proxy.Type.DIRECT) == false) && ((proxyPort == 0) || Strings.isEmpty(proxyHost))) {
|
|
||||||
throw new SettingsException("Azure Proxy type has been set but proxy host or port is not defined.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (proxyType.equals(Proxy.Type.DIRECT)) {
|
|
||||||
proxy = null;
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
proxy = new Proxy(proxyType, new InetSocketAddress(InetAddress.getByName(proxyHost), proxyPort));
|
|
||||||
} catch (final UnknownHostException e) {
|
|
||||||
throw new SettingsException("Azure proxy host is unknown.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.locationMode = LocationMode.PRIMARY_ONLY;
|
this.locationMode = LocationMode.PRIMARY_ONLY;
|
||||||
this.connectTimeout = connectTimeout;
|
this.connectTimeout = connectTimeout;
|
||||||
this.writeTimeout = writeTimeout;
|
this.writeTimeout = writeTimeout;
|
||||||
this.readTimeout = readTimeout;
|
this.readTimeout = readTimeout;
|
||||||
this.responseTimeout = responseTimeout;
|
this.responseTimeout = responseTimeout;
|
||||||
|
this.proxySettings = proxySettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getEndpointSuffix() {
|
public String getEndpointSuffix() {
|
||||||
|
@ -268,8 +270,8 @@ final class AzureStorageSettings {
|
||||||
return maxRetries;
|
return maxRetries;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Proxy getProxy() {
|
public ProxySettings getProxySettings() {
|
||||||
return proxy;
|
return proxySettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getConnectString() {
|
public String getConnectString() {
|
||||||
|
@ -325,7 +327,7 @@ final class AzureStorageSettings {
|
||||||
sb.append(", timeout=").append(timeout);
|
sb.append(", timeout=").append(timeout);
|
||||||
sb.append(", endpointSuffix='").append(endpointSuffix).append('\'');
|
sb.append(", endpointSuffix='").append(endpointSuffix).append('\'');
|
||||||
sb.append(", maxRetries=").append(maxRetries);
|
sb.append(", maxRetries=").append(maxRetries);
|
||||||
sb.append(", proxy=").append(proxy);
|
sb.append(", proxySettings=").append(proxySettings != ProxySettings.NO_PROXY_SETTINGS ? "PROXY_SET" : "PROXY_NOT_SET");
|
||||||
sb.append(", locationMode='").append(locationMode).append('\'');
|
sb.append(", locationMode='").append(locationMode).append('\'');
|
||||||
sb.append(", connectTimeout='").append(connectTimeout).append('\'');
|
sb.append(", connectTimeout='").append(connectTimeout).append('\'');
|
||||||
sb.append(", writeTimeout='").append(writeTimeout).append('\'');
|
sb.append(", writeTimeout='").append(writeTimeout).append('\'');
|
||||||
|
@ -371,17 +373,42 @@ final class AzureStorageSettings {
|
||||||
getValue(settings, clientName, ENDPOINT_SUFFIX_SETTING),
|
getValue(settings, clientName, ENDPOINT_SUFFIX_SETTING),
|
||||||
getValue(settings, clientName, TIMEOUT_SETTING),
|
getValue(settings, clientName, TIMEOUT_SETTING),
|
||||||
getValue(settings, clientName, MAX_RETRIES_SETTING),
|
getValue(settings, clientName, MAX_RETRIES_SETTING),
|
||||||
getValue(settings, clientName, PROXY_TYPE_SETTING),
|
|
||||||
getValue(settings, clientName, PROXY_HOST_SETTING),
|
|
||||||
getValue(settings, clientName, PROXY_PORT_SETTING),
|
|
||||||
getValue(settings, clientName, CONNECT_TIMEOUT_SETTING),
|
getValue(settings, clientName, CONNECT_TIMEOUT_SETTING),
|
||||||
getValue(settings, clientName, WRITE_TIMEOUT_SETTING),
|
getValue(settings, clientName, WRITE_TIMEOUT_SETTING),
|
||||||
getValue(settings, clientName, READ_TIMEOUT_SETTING),
|
getValue(settings, clientName, READ_TIMEOUT_SETTING),
|
||||||
getValue(settings, clientName, RESPONSE_TIMEOUT_SETTING)
|
getValue(settings, clientName, RESPONSE_TIMEOUT_SETTING),
|
||||||
|
validateAndCreateProxySettings(settings, clientName)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ProxySettings validateAndCreateProxySettings(final Settings settings, final String clientName) {
|
||||||
|
final ProxySettings.ProxyType proxyType = getConfigValue(settings, clientName, PROXY_TYPE_SETTING);
|
||||||
|
final String proxyHost = getConfigValue(settings, clientName, PROXY_HOST_SETTING);
|
||||||
|
final int proxyPort = getConfigValue(settings, clientName, PROXY_PORT_SETTING);
|
||||||
|
final SecureString proxyUserName = getConfigValue(settings, clientName, PROXY_USERNAME_SETTING);
|
||||||
|
final SecureString proxyPassword = getConfigValue(settings, clientName, PROXY_PASSWORD_SETTING);
|
||||||
|
// Validate proxy settings
|
||||||
|
if (proxyType == ProxySettings.ProxyType.DIRECT
|
||||||
|
&& (proxyPort != 0 || Strings.hasText(proxyHost) || Strings.hasText(proxyUserName) || Strings.hasText(proxyPassword))) {
|
||||||
|
throw new SettingsException("Azure proxy port or host or username or password have been set but proxy type is not defined.");
|
||||||
|
}
|
||||||
|
if (proxyType != ProxySettings.ProxyType.DIRECT && (proxyPort == 0 || Strings.isEmpty(proxyHost))) {
|
||||||
|
throw new SettingsException("Azure proxy type has been set but proxy host or port is not defined.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proxyType == ProxySettings.ProxyType.DIRECT) {
|
||||||
|
return ProxySettings.NO_PROXY_SETTINGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final InetAddress proxyHostAddress = InetAddress.getByName(proxyHost);
|
||||||
|
return new ProxySettings(proxyType, proxyHostAddress, proxyPort, proxyUserName.toString(), proxyPassword.toString());
|
||||||
|
} catch (final UnknownHostException e) {
|
||||||
|
throw new SettingsException("Azure proxy host is unknown.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static <T> T getConfigValue(Settings settings, String clientName, Setting.AffixSetting<T> clientSetting) {
|
private static <T> T getConfigValue(Settings settings, String clientName, Setting.AffixSetting<T> clientSetting) {
|
||||||
final Setting<T> concreteSetting = clientSetting.getConcreteSettingForNamespace(clientName);
|
final Setting<T> concreteSetting = clientSetting.getConcreteSettingForNamespace(clientName);
|
||||||
return concreteSetting.get(settings);
|
return concreteSetting.get(settings);
|
||||||
|
@ -407,12 +434,12 @@ final class AzureStorageSettings {
|
||||||
entry.getValue().endpointSuffix,
|
entry.getValue().endpointSuffix,
|
||||||
entry.getValue().timeout,
|
entry.getValue().timeout,
|
||||||
entry.getValue().maxRetries,
|
entry.getValue().maxRetries,
|
||||||
entry.getValue().proxy,
|
|
||||||
locationMode,
|
locationMode,
|
||||||
entry.getValue().connectTimeout,
|
entry.getValue().connectTimeout,
|
||||||
entry.getValue().writeTimeout,
|
entry.getValue().writeTimeout,
|
||||||
entry.getValue().readTimeout,
|
entry.getValue().readTimeout,
|
||||||
entry.getValue().responseTimeout
|
entry.getValue().responseTimeout,
|
||||||
|
entry.getValue().getProxySettings()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
* 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.repositories.azure;
|
||||||
|
|
||||||
|
import com.azure.core.http.ProxyOptions;
|
||||||
|
import org.opensearch.common.Strings;
|
||||||
|
import org.opensearch.common.settings.SettingsException;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class ProxySettings {
|
||||||
|
|
||||||
|
public static final ProxySettings NO_PROXY_SETTINGS = new ProxySettings(ProxyType.DIRECT, null, -1, null, null);
|
||||||
|
|
||||||
|
private final ProxyType type;
|
||||||
|
|
||||||
|
private final InetAddress host;
|
||||||
|
|
||||||
|
private final String username;
|
||||||
|
|
||||||
|
private final String password;
|
||||||
|
|
||||||
|
private final int port;
|
||||||
|
|
||||||
|
public static enum ProxyType {
|
||||||
|
HTTP(ProxyOptions.Type.HTTP.name()),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Please use SOCKS4 instead
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
SOCKS(ProxyOptions.Type.SOCKS4.name()),
|
||||||
|
|
||||||
|
SOCKS4(ProxyOptions.Type.SOCKS4.name()),
|
||||||
|
|
||||||
|
SOCKS5(ProxyOptions.Type.SOCKS5.name()),
|
||||||
|
|
||||||
|
DIRECT("DIRECT");
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
private ProxyType(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProxyOptions.Type toProxyType() {
|
||||||
|
if (this == DIRECT) {
|
||||||
|
// We check it in settings,
|
||||||
|
// the probability that it could be thrown is small, but how knows
|
||||||
|
throw new SettingsException("Couldn't convert to Azure proxy type");
|
||||||
|
}
|
||||||
|
return ProxyOptions.Type.valueOf(name());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProxySettings(final ProxyType type, final InetAddress host, final int port, final String username, final String password) {
|
||||||
|
this.type = type;
|
||||||
|
this.host = host;
|
||||||
|
this.port = port;
|
||||||
|
this.username = username;
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProxyType getType() {
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InetSocketAddress getAddress() {
|
||||||
|
return new InetSocketAddress(host, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return this.username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return this.password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAuthenticated() {
|
||||||
|
return Strings.isNullOrEmpty(username) == false && Strings.isNullOrEmpty(password) == false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
final ProxySettings that = (ProxySettings) o;
|
||||||
|
return port == that.port
|
||||||
|
&& type == that.type
|
||||||
|
&& Objects.equals(host, that.host)
|
||||||
|
&& Objects.equals(username, that.username)
|
||||||
|
&& Objects.equals(password, that.password);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(type, host, username, password, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -38,4 +38,7 @@ grant {
|
||||||
permission java.lang.RuntimePermission "accessDeclaredMembers";
|
permission java.lang.RuntimePermission "accessDeclaredMembers";
|
||||||
permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
|
permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
|
||||||
permission java.lang.RuntimePermission "setContextClassLoader";
|
permission java.lang.RuntimePermission "setContextClassLoader";
|
||||||
|
|
||||||
|
// azure client set Authenticator for proxy username/password
|
||||||
|
permission java.net.NetPermission "setDefaultAuthenticator";
|
||||||
};
|
};
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
|
|
||||||
package org.opensearch.repositories.azure;
|
package org.opensearch.repositories.azure;
|
||||||
|
|
||||||
|
import org.opensearch.common.Strings;
|
||||||
import reactor.core.scheduler.Schedulers;
|
import reactor.core.scheduler.Schedulers;
|
||||||
|
|
||||||
import com.azure.core.http.policy.HttpPipelinePolicy;
|
import com.azure.core.http.policy.HttpPipelinePolicy;
|
||||||
|
@ -50,7 +51,6 @@ import java.io.IOException;
|
||||||
import java.io.UncheckedIOException;
|
import java.io.UncheckedIOException;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.Proxy;
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
@ -299,9 +299,9 @@ public class AzureStorageServiceTests extends OpenSearchTestCase {
|
||||||
public void testNoProxy() {
|
public void testNoProxy() {
|
||||||
final Settings settings = Settings.builder().setSecureSettings(buildSecureSettings()).build();
|
final Settings settings = Settings.builder().setSecureSettings(buildSecureSettings()).build();
|
||||||
final AzureStorageService mock = storageServiceWithSettingsValidation(settings);
|
final AzureStorageService mock = storageServiceWithSettingsValidation(settings);
|
||||||
assertThat(mock.storageSettings.get("azure1").getProxy(), nullValue());
|
assertEquals(mock.storageSettings.get("azure1").getProxySettings(), ProxySettings.NO_PROXY_SETTINGS);
|
||||||
assertThat(mock.storageSettings.get("azure2").getProxy(), nullValue());
|
assertEquals(mock.storageSettings.get("azure2").getProxySettings(), ProxySettings.NO_PROXY_SETTINGS);
|
||||||
assertThat(mock.storageSettings.get("azure3").getProxy(), nullValue());
|
assertEquals(mock.storageSettings.get("azure3").getProxySettings(), ProxySettings.NO_PROXY_SETTINGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testProxyHttp() throws UnknownHostException {
|
public void testProxyHttp() throws UnknownHostException {
|
||||||
|
@ -312,13 +312,13 @@ public class AzureStorageServiceTests extends OpenSearchTestCase {
|
||||||
.put("azure.client.azure1.proxy.type", "http")
|
.put("azure.client.azure1.proxy.type", "http")
|
||||||
.build();
|
.build();
|
||||||
final AzureStorageService mock = storageServiceWithSettingsValidation(settings);
|
final AzureStorageService mock = storageServiceWithSettingsValidation(settings);
|
||||||
final Proxy azure1Proxy = mock.storageSettings.get("azure1").getProxy();
|
final ProxySettings azure1Proxy = mock.storageSettings.get("azure1").getProxySettings();
|
||||||
|
|
||||||
assertThat(azure1Proxy, notNullValue());
|
assertThat(azure1Proxy, notNullValue());
|
||||||
assertThat(azure1Proxy.type(), is(Proxy.Type.HTTP));
|
assertThat(azure1Proxy.getType(), is(ProxySettings.ProxyType.HTTP));
|
||||||
assertThat(azure1Proxy.address(), is(new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 8080)));
|
assertThat(azure1Proxy.getAddress(), is(new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 8080)));
|
||||||
assertThat(mock.storageSettings.get("azure2").getProxy(), nullValue());
|
assertEquals(ProxySettings.NO_PROXY_SETTINGS, mock.storageSettings.get("azure2").getProxySettings());
|
||||||
assertThat(mock.storageSettings.get("azure3").getProxy(), nullValue());
|
assertEquals(ProxySettings.NO_PROXY_SETTINGS, mock.storageSettings.get("azure3").getProxySettings());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testMultipleProxies() throws UnknownHostException {
|
public void testMultipleProxies() throws UnknownHostException {
|
||||||
|
@ -332,52 +332,59 @@ public class AzureStorageServiceTests extends OpenSearchTestCase {
|
||||||
.put("azure.client.azure2.proxy.type", "http")
|
.put("azure.client.azure2.proxy.type", "http")
|
||||||
.build();
|
.build();
|
||||||
final AzureStorageService mock = storageServiceWithSettingsValidation(settings);
|
final AzureStorageService mock = storageServiceWithSettingsValidation(settings);
|
||||||
final Proxy azure1Proxy = mock.storageSettings.get("azure1").getProxy();
|
final ProxySettings azure1Proxy = mock.storageSettings.get("azure1").getProxySettings();
|
||||||
assertThat(azure1Proxy, notNullValue());
|
assertThat(azure1Proxy, notNullValue());
|
||||||
assertThat(azure1Proxy.type(), is(Proxy.Type.HTTP));
|
assertThat(azure1Proxy.getType(), is(ProxySettings.ProxyType.HTTP));
|
||||||
assertThat(azure1Proxy.address(), is(new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 8080)));
|
assertThat(azure1Proxy.getAddress(), is(new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 8080)));
|
||||||
final Proxy azure2Proxy = mock.storageSettings.get("azure2").getProxy();
|
final ProxySettings azure2Proxy = mock.storageSettings.get("azure2").getProxySettings();
|
||||||
assertThat(azure2Proxy, notNullValue());
|
assertThat(azure2Proxy, notNullValue());
|
||||||
assertThat(azure2Proxy.type(), is(Proxy.Type.HTTP));
|
assertThat(azure2Proxy.getType(), is(ProxySettings.ProxyType.HTTP));
|
||||||
assertThat(azure2Proxy.address(), is(new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 8081)));
|
assertThat(azure2Proxy.getAddress(), is(new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 8081)));
|
||||||
assertThat(mock.storageSettings.get("azure3").getProxy(), nullValue());
|
assertTrue(Strings.isNullOrEmpty(azure2Proxy.getUsername()));
|
||||||
|
assertTrue(Strings.isNullOrEmpty(azure2Proxy.getPassword()));
|
||||||
|
assertEquals(mock.storageSettings.get("azure3").getProxySettings(), ProxySettings.NO_PROXY_SETTINGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testProxySocks() throws UnknownHostException {
|
public void testProxySocks() throws UnknownHostException {
|
||||||
|
final MockSecureSettings secureSettings = buildSecureSettings();
|
||||||
|
secureSettings.setString("azure.client.azure1.proxy.username", "user");
|
||||||
|
secureSettings.setString("azure.client.azure1.proxy.password", "pwd");
|
||||||
final Settings settings = Settings.builder()
|
final Settings settings = Settings.builder()
|
||||||
.setSecureSettings(buildSecureSettings())
|
|
||||||
.put("azure.client.azure1.proxy.host", "127.0.0.1")
|
.put("azure.client.azure1.proxy.host", "127.0.0.1")
|
||||||
.put("azure.client.azure1.proxy.port", 8080)
|
.put("azure.client.azure1.proxy.port", 8080)
|
||||||
.put("azure.client.azure1.proxy.type", "socks")
|
.put("azure.client.azure1.proxy.type", "socks5")
|
||||||
|
.setSecureSettings(secureSettings)
|
||||||
.build();
|
.build();
|
||||||
final AzureStorageService mock = storageServiceWithSettingsValidation(settings);
|
final AzureStorageService mock = storageServiceWithSettingsValidation(settings);
|
||||||
final Proxy azure1Proxy = mock.storageSettings.get("azure1").getProxy();
|
final ProxySettings azure1Proxy = mock.storageSettings.get("azure1").getProxySettings();
|
||||||
assertThat(azure1Proxy, notNullValue());
|
assertThat(azure1Proxy, notNullValue());
|
||||||
assertThat(azure1Proxy.type(), is(Proxy.Type.SOCKS));
|
assertThat(azure1Proxy.getType(), is(ProxySettings.ProxyType.SOCKS5));
|
||||||
assertThat(azure1Proxy.address(), is(new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 8080)));
|
assertThat(azure1Proxy.getAddress(), is(new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 8080)));
|
||||||
assertThat(mock.storageSettings.get("azure2").getProxy(), nullValue());
|
assertEquals("user", azure1Proxy.getUsername());
|
||||||
assertThat(mock.storageSettings.get("azure3").getProxy(), nullValue());
|
assertEquals("pwd", azure1Proxy.getPassword());
|
||||||
|
assertEquals(ProxySettings.NO_PROXY_SETTINGS, mock.storageSettings.get("azure2").getProxySettings());
|
||||||
|
assertEquals(ProxySettings.NO_PROXY_SETTINGS, mock.storageSettings.get("azure3").getProxySettings());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testProxyNoHost() {
|
public void testProxyNoHost() {
|
||||||
final Settings settings = Settings.builder()
|
final Settings settings = Settings.builder()
|
||||||
.setSecureSettings(buildSecureSettings())
|
.setSecureSettings(buildSecureSettings())
|
||||||
.put("azure.client.azure1.proxy.port", 8080)
|
.put("azure.client.azure1.proxy.port", 8080)
|
||||||
.put("azure.client.azure1.proxy.type", randomFrom("socks", "http"))
|
.put("azure.client.azure1.proxy.type", randomFrom("socks", "socks4", "socks5", "http"))
|
||||||
.build();
|
.build();
|
||||||
final SettingsException e = expectThrows(SettingsException.class, () -> storageServiceWithSettingsValidation(settings));
|
final SettingsException e = expectThrows(SettingsException.class, () -> storageServiceWithSettingsValidation(settings));
|
||||||
assertEquals("Azure Proxy type has been set but proxy host or port is not defined.", e.getMessage());
|
assertEquals("Azure proxy type has been set but proxy host or port is not defined.", e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testProxyNoPort() {
|
public void testProxyNoPort() {
|
||||||
final Settings settings = Settings.builder()
|
final Settings settings = Settings.builder()
|
||||||
.setSecureSettings(buildSecureSettings())
|
.setSecureSettings(buildSecureSettings())
|
||||||
.put("azure.client.azure1.proxy.host", "127.0.0.1")
|
.put("azure.client.azure1.proxy.host", "127.0.0.1")
|
||||||
.put("azure.client.azure1.proxy.type", randomFrom("socks", "http"))
|
.put("azure.client.azure1.proxy.type", randomFrom("socks", "socks4", "socks5", "http"))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
final SettingsException e = expectThrows(SettingsException.class, () -> storageServiceWithSettingsValidation(settings));
|
final SettingsException e = expectThrows(SettingsException.class, () -> storageServiceWithSettingsValidation(settings));
|
||||||
assertEquals("Azure Proxy type has been set but proxy host or port is not defined.", e.getMessage());
|
assertEquals("Azure proxy type has been set but proxy host or port is not defined.", e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testProxyNoType() {
|
public void testProxyNoType() {
|
||||||
|
@ -388,13 +395,13 @@ public class AzureStorageServiceTests extends OpenSearchTestCase {
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
final SettingsException e = expectThrows(SettingsException.class, () -> storageServiceWithSettingsValidation(settings));
|
final SettingsException e = expectThrows(SettingsException.class, () -> storageServiceWithSettingsValidation(settings));
|
||||||
assertEquals("Azure Proxy port or host have been set but proxy type is not defined.", e.getMessage());
|
assertEquals("Azure proxy port or host or username or password have been set but proxy type is not defined.", e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testProxyWrongHost() {
|
public void testProxyWrongHost() {
|
||||||
final Settings settings = Settings.builder()
|
final Settings settings = Settings.builder()
|
||||||
.setSecureSettings(buildSecureSettings())
|
.setSecureSettings(buildSecureSettings())
|
||||||
.put("azure.client.azure1.proxy.type", randomFrom("socks", "http"))
|
.put("azure.client.azure1.proxy.type", randomFrom("socks", "socks4", "socks5", "http"))
|
||||||
.put("azure.client.azure1.proxy.host", "thisisnotavalidhostorwehavebeensuperunlucky")
|
.put("azure.client.azure1.proxy.host", "thisisnotavalidhostorwehavebeensuperunlucky")
|
||||||
.put("azure.client.azure1.proxy.port", 8080)
|
.put("azure.client.azure1.proxy.port", 8080)
|
||||||
.build();
|
.build();
|
||||||
|
|
Loading…
Reference in New Issue