Skip to content

Commit

Permalink
Add proxy username and password settings for Azure repository (#2098)
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
willyborankin authored Feb 15, 2022
1 parent 6b6f033 commit 62361ce
Show file tree
Hide file tree
Showing 6 changed files with 238 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,15 @@ public List<Setting<?>> getSettings() {
AzureStorageSettings.ENDPOINT_SUFFIX_SETTING,
AzureStorageSettings.TIMEOUT_SETTING,
AzureStorageSettings.MAX_RETRIES_SETTING,
AzureStorageSettings.PROXY_TYPE_SETTING,
AzureStorageSettings.PROXY_HOST_SETTING,
AzureStorageSettings.PROXY_PORT_SETTING,
AzureStorageSettings.CONNECT_TIMEOUT_SETTING,
AzureStorageSettings.WRITE_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
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
import com.azure.core.http.HttpRequest;
import com.azure.core.http.HttpResponse;
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.policy.HttpPipelinePolicy;
import com.azure.core.util.Configuration;
Expand All @@ -66,12 +65,11 @@
import org.opensearch.common.unit.ByteSizeValue;
import org.opensearch.common.unit.TimeValue;

import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.net.URISyntaxException;
import java.security.InvalidKeyException;
import java.time.Duration;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
Expand Down Expand Up @@ -169,15 +167,20 @@ private ClientState buildClient(AzureStorageSettings azureStorageSettings, BiCon
final NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup(new NioThreadFactory());
final NettyAsyncHttpClientBuilder clientBuilder = new NettyAsyncHttpClientBuilder().eventLoopGroup(eventLoopGroup);

final Proxy proxy = azureStorageSettings.getProxy();
if (proxy != null) {
final Type type = Arrays.stream(Type.values())
.filter(t -> t.toProxyType().equals(proxy.type()))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("Unsupported proxy type: " + proxy.type()));

clientBuilder.proxy(new ProxyOptions(type, (InetSocketAddress) proxy.address()));
}
SocketAccess.doPrivilegedVoidException(() -> {
final ProxySettings proxySettings = azureStorageSettings.getProxySettings();
if (proxySettings != ProxySettings.NO_PROXY_SETTINGS) {
if (proxySettings.isAuthenticated()) {
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(proxySettings.getUsername(), proxySettings.getPassword().toCharArray());
}
});
}
clientBuilder.proxy(new ProxyOptions(proxySettings.getType().toProxyType(), proxySettings.getAddress()));
}
});

final TimeValue connectTimeout = azureStorageSettings.getConnectTimeout();
if (connectTimeout != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@
import org.opensearch.common.settings.SettingsException;
import org.opensearch.common.unit.TimeValue;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.UnknownHostException;
import java.util.Collections;
import java.util.HashMap;
Expand Down Expand Up @@ -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 */
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,
"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,
() -> KEY_SETTING
);
Expand All @@ -162,27 +160,50 @@ final class AzureStorageSettings {
);

/** 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,
"proxy.port",
(key) -> Setting.intSetting(key, 0, 0, 65535, Setting.Property.NodeScope),
() -> KEY_SETTING,
() -> ACCOUNT_SETTING,
() -> PROXY_TYPE_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 connectString;
private final String endpointSuffix;
private final TimeValue timeout;
private final int maxRetries;
private final Proxy proxy;
private final LocationMode locationMode;
private final TimeValue connectTimeout;
private final TimeValue writeTimeout;
private final TimeValue readTimeout;
private final TimeValue responseTimeout;
private final ProxySettings proxySettings;

// copy-constructor
private AzureStorageSettings(
Expand All @@ -191,24 +212,24 @@ private AzureStorageSettings(
String endpointSuffix,
TimeValue timeout,
int maxRetries,
Proxy proxy,
LocationMode locationMode,
TimeValue connectTimeout,
TimeValue writeTimeout,
TimeValue readTimeout,
TimeValue responseTimeout
TimeValue responseTimeout,
ProxySettings proxySettings
) {
this.account = account;
this.connectString = connectString;
this.endpointSuffix = endpointSuffix;
this.timeout = timeout;
this.maxRetries = maxRetries;
this.proxy = proxy;
this.locationMode = locationMode;
this.connectTimeout = connectTimeout;
this.writeTimeout = writeTimeout;
this.readTimeout = readTimeout;
this.responseTimeout = responseTimeout;
this.proxySettings = proxySettings;
}

private AzureStorageSettings(
Expand All @@ -218,42 +239,23 @@ private AzureStorageSettings(
String endpointSuffix,
TimeValue timeout,
int maxRetries,
Proxy.Type proxyType,
String proxyHost,
Integer proxyPort,
TimeValue connectTimeout,
TimeValue writeTimeout,
TimeValue readTimeout,
TimeValue responseTimeout
TimeValue responseTimeout,
ProxySettings proxySettings
) {
this.account = account;
this.connectString = buildConnectString(account, key, sasToken, endpointSuffix);
this.endpointSuffix = endpointSuffix;
this.timeout = timeout;
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.connectTimeout = connectTimeout;
this.writeTimeout = writeTimeout;
this.readTimeout = readTimeout;
this.responseTimeout = responseTimeout;
this.proxySettings = proxySettings;
}

public String getEndpointSuffix() {
Expand All @@ -268,8 +270,8 @@ public int getMaxRetries() {
return maxRetries;
}

public Proxy getProxy() {
return proxy;
public ProxySettings getProxySettings() {
return proxySettings;
}

public String getConnectString() {
Expand Down Expand Up @@ -325,7 +327,7 @@ public String toString() {
sb.append(", timeout=").append(timeout);
sb.append(", endpointSuffix='").append(endpointSuffix).append('\'');
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(", connectTimeout='").append(connectTimeout).append('\'');
sb.append(", writeTimeout='").append(writeTimeout).append('\'');
Expand Down Expand Up @@ -371,17 +373,42 @@ private static AzureStorageSettings getClientSettings(Settings settings, String
getValue(settings, clientName, ENDPOINT_SUFFIX_SETTING),
getValue(settings, clientName, TIMEOUT_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, WRITE_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) {
final Setting<T> concreteSetting = clientSetting.getConcreteSettingForNamespace(clientName);
return concreteSetting.get(settings);
Expand All @@ -407,12 +434,12 @@ static Map<String, AzureStorageSettings> overrideLocationMode(
entry.getValue().endpointSuffix,
entry.getValue().timeout,
entry.getValue().maxRetries,
entry.getValue().proxy,
locationMode,
entry.getValue().connectTimeout,
entry.getValue().writeTimeout,
entry.getValue().readTimeout,
entry.getValue().responseTimeout
entry.getValue().responseTimeout,
entry.getValue().getProxySettings()
)
);
}
Expand Down
Loading

0 comments on commit 62361ce

Please sign in to comment.