com.azure.core.amqp.ProxyOptions Maven / Gradle / Ivy
Show all versions of azure-core-amqp Show documentation
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.azure.core.amqp;
import com.azure.core.annotation.Immutable;
import com.azure.core.util.Configuration;
import com.azure.core.util.ConfigurationProperty;
import com.azure.core.util.ConfigurationPropertyBuilder;
import com.azure.core.util.CoreUtils;
import com.azure.core.util.logging.ClientLogger;
import java.net.InetSocketAddress;
import java.net.PasswordAuthentication;
import java.net.Proxy;
import java.util.Arrays;
import java.util.Objects;
import java.util.regex.Pattern;
/**
* Properties for configuring proxies with Event Hubs.
*/
@Immutable
public class ProxyOptions implements AutoCloseable {
/**
* The configuration key for containing the username who authenticates with the proxy.
*/
public static final String PROXY_USERNAME = "PROXY_USERNAME";
/**
* The configuration key for containing the password for the username who authenticates with the proxy.
*/
public static final String PROXY_PASSWORD = "PROXY_PASSWORD";
/**
* The configuration key for containing the authentication type to be used by the proxy.
* This can one of three values -
* - NONE
* - BASIC
* - DIGEST
* as defined in ProxyAuthenticationType
*/
public static final String PROXY_AUTHENTICATION_TYPE = "PROXY_AUTHENTICATION_TYPE";
private static final ConfigurationProperty AUTH_TYPE_PROPERTY
= new ConfigurationPropertyBuilder<>(ConfigurationProperties.AMQP_PROXY_AUTHENTICATION_TYPE,
s -> ProxyAuthenticationType.valueOf(s)).shared(true)
.logValue(true)
.defaultValue(ProxyAuthenticationType.NONE)
.build();
private static final ConfigurationProperty TYPE_PROPERTY
= new ConfigurationPropertyBuilder<>(ConfigurationProperties.AMQP_PROXY_TYPE, s -> Proxy.Type.valueOf(s))
.shared(true)
.logValue(true)
.defaultValue(Proxy.Type.HTTP)
.build();
private static final ConfigurationProperty HOST_PROPERTY
= ConfigurationPropertyBuilder.ofString(ConfigurationProperties.AMQP_PROXY_HOST)
.shared(true)
.logValue(true)
.build();
private static final ConfigurationProperty PORT_PROPERTY
= ConfigurationPropertyBuilder.ofInteger(ConfigurationProperties.AMQP_PROXY_PORT)
.shared(true)
.required(true)
.build();
private static final ConfigurationProperty USER_PROPERTY
= ConfigurationPropertyBuilder.ofString(ConfigurationProperties.AMQP_PROXY_USER)
.shared(true)
.logValue(true)
.build();
private static final ConfigurationProperty PASSWORD_PROPERTY
= ConfigurationPropertyBuilder.ofString(ConfigurationProperties.AMQP_PROXY_PASSWORD).shared(true).build();
private static final ClientLogger LOGGER = new ClientLogger(ProxyOptions.class);
private static final Pattern HOST_PORT_PATTERN = Pattern.compile("^[^:]+:\\d+");
private final PasswordAuthentication credentials;
private final Proxy proxyAddress;
private final ProxyAuthenticationType authentication;
/**
* Gets the system defaults for proxy configuration and authentication.
*/
public static final ProxyOptions SYSTEM_DEFAULTS = new ProxyOptions();
private ProxyOptions() {
this.credentials = null;
this.proxyAddress = null;
this.authentication = ProxyAuthenticationType.NONE;
}
/**
* Creates a proxy configuration that uses the {@code proxyAddress} and authenticates with provided
* {@code username}, {@code password} and {@code authentication}.
*
* @param authentication Authentication method to preemptively use with proxy.
* @param proxyAddress Proxy to use. If {@code null} is passed in, then the system configured {@link java.net.Proxy}
* is used.
* @param username Optional. Username used to authenticate with proxy. If not specified, the system-wide
* {@link java.net.Authenticator} is used to fetch credentials.
* @param password Optional. Password used to authenticate with proxy.
* @throws NullPointerException if {@code authentication} is {@code null}.
* @throws IllegalArgumentException if {@code authentication} is {@link ProxyAuthenticationType#BASIC} or
* {@link ProxyAuthenticationType#DIGEST} and {@code username} or {@code password} are {@code null}.
*/
public ProxyOptions(ProxyAuthenticationType authentication, Proxy proxyAddress, String username, String password) {
this.authentication = Objects.requireNonNull(authentication, "'authentication' cannot be null.");
this.proxyAddress = proxyAddress;
if (username != null && password != null) {
this.credentials = new PasswordAuthentication(username, password.toCharArray());
} else {
LOGGER.info("Username or password is null. Using system-wide authentication.");
this.credentials = null;
}
}
/**
* Attempts to load a proxy from the configuration.
*
* @param configuration The {@link Configuration} that is used to load proxy configurations from the environment. If
* {@code null} is passed then {@link Configuration#getGlobalConfiguration()} will be used.
* @return A {@link ProxyOptions} reflecting a proxy loaded from the environment, if no proxy is found {@code null}
* will be returned.
*
* @throws RuntimeException If passed {@link Configuration} contains invalid configuration options,
* {@link RuntimeException} is thrown.
*/
public static ProxyOptions fromConfiguration(Configuration configuration) {
if (configuration == Configuration.NONE) {
return SYSTEM_DEFAULTS;
}
configuration = (configuration == null) ? Configuration.getGlobalConfiguration() : configuration;
String host = configuration.get(HOST_PROPERTY);
if (CoreUtils.isNullOrEmpty(host)) {
return loadFromEnvironmentConfiguration(configuration);
}
int port = configuration.get(PORT_PROPERTY);
InetSocketAddress socketAddress = new InetSocketAddress(host, port);
Proxy.Type proxyType = configuration.get(TYPE_PROPERTY);
ProxyAuthenticationType authType = configuration.get(AUTH_TYPE_PROPERTY);
String username = configuration.get(USER_PROPERTY);
String password = configuration.get(PASSWORD_PROPERTY);
return new ProxyOptions(authType, new Proxy(proxyType, socketAddress), username, password);
}
/**
* Gets the proxy authentication type.
*
* @return the proxy authentication type to use. Returns {@code null} if no authentication type was set. This occurs
* when user uses {@link ProxyOptions#SYSTEM_DEFAULTS}.
*/
public ProxyAuthenticationType getAuthentication() {
return this.authentication;
}
/**
* Gets the proxy address.
*
* @return the proxy address. Return {@code null} if no proxy address was set This occurs when user uses
* {@link ProxyOptions#SYSTEM_DEFAULTS}.
*/
public Proxy getProxyAddress() {
return this.proxyAddress;
}
/**
* Gets the credentials user provided for authentication of proxy server.
*
* @return the username and password to use. Return {@code null} if no credential was set. This occurs when user
* uses {@link ProxyOptions#SYSTEM_DEFAULTS}.
*/
public PasswordAuthentication getCredential() {
return this.credentials;
}
/**
* Gets whether the user has defined credentials.
*
* @return true if the user has defined the credentials to use, false otherwise.
*/
public boolean hasUserDefinedCredentials() {
return credentials != null;
}
/**
* Gets whether the proxy address has been configured. Used to determine whether to use system-defined or
* user-defined proxy.
*
* @return true if the proxy url has been set, and false otherwise.
*/
public boolean isProxyAddressConfigured() {
return proxyAddress != null && proxyAddress.address() != null;
}
/**
* Disposes of the configuration along with potential credentials.
*/
@Override
public void close() {
if (credentials != null) {
Arrays.fill(credentials.getPassword(), '\0');
}
}
private static ProxyOptions loadFromEnvironmentConfiguration(Configuration configuration) {
final String proxyAddress = configuration.get(Configuration.PROPERTY_HTTP_PROXY);
if (CoreUtils.isNullOrEmpty(proxyAddress)) {
return ProxyOptions.SYSTEM_DEFAULTS;
}
final String authTypeStr = configuration.get(PROXY_AUTHENTICATION_TYPE);
final ProxyAuthenticationType authentication
= authTypeStr != null ? ProxyAuthenticationType.valueOf(authTypeStr) : ProxyAuthenticationType.NONE;
if (HOST_PORT_PATTERN.matcher(proxyAddress.trim()).find()) {
final String[] hostPort = proxyAddress.split(":");
final String host = hostPort[0];
final int port = Integer.parseInt(hostPort[1]);
final Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port));
final String username = configuration.get(ProxyOptions.PROXY_USERNAME);
final String password = configuration.get(ProxyOptions.PROXY_PASSWORD);
return new ProxyOptions(authentication, proxy, username, password);
} else if (Boolean.parseBoolean(configuration.get("java.net.useSystemProxies"))) {
// java.net.useSystemProxies needs to be set to true in this scenario.
// If it is set to false 'ProxyOptions' in azure-core will return null.
com.azure.core.http.ProxyOptions httpProxyOptions
= com.azure.core.http.ProxyOptions.fromConfiguration(configuration);
if (httpProxyOptions != null) {
return new ProxyOptions(authentication,
new Proxy(httpProxyOptions.getType().toProxyType(), httpProxyOptions.getAddress()),
httpProxyOptions.getUsername(), httpProxyOptions.getPassword());
}
}
LOGGER.verbose(
"'HTTP_PROXY' was configured but ignored as 'java.net.useSystemProxies' wasn't " + "set or was false.");
return ProxyOptions.SYSTEM_DEFAULTS;
}
/**
* Lists available configuration property names for AMQP {@link ProxyOptions}.
*/
private static class ConfigurationProperties {
/**
* The AMQP proxy server authentication type that match {@link ProxyAuthenticationType} enum.
* Supported values are {@code NONE} (no authentication), {@code BASIC} or {@code DIGEST}.
* If unsupported value is provided, {@link IllegalArgumentException} will be thrown at retrieval time in
* {@link ProxyOptions#fromConfiguration(Configuration)}
*
* Default value is {@code NONE}.
*/
public static final String AMQP_PROXY_AUTHENTICATION_TYPE = "amqp.proxy.authentication-type";
/**
* The AMQP proxy server type that match {@link Proxy.Type} enum.
* Supported values are {@code HTTP} or {@code SOCKS}.
* If unsupported value is provided, {@link IllegalArgumentException} will be thrown at retrieval time in
* {@link ProxyOptions#fromConfiguration(Configuration)}
*
* Default value is {@code DIRECT} (no proxy).
*/
public static final String AMQP_PROXY_TYPE = "amqp.proxy.type";
/**
* The AMQP host name of the proxy server.
* Default value is {@code null}.
*/
public static final String AMQP_PROXY_HOST = "amqp.proxy.hostname";
/**
* The port number of the AMQP proxy server.
* Required if {@code amqp.proxy.hostname} is set.
*/
public static final String AMQP_PROXY_PORT = "amqp.proxy.port";
/**
* The AMQP proxy server user.
* Default value is {@code null}.
*/
public static final String AMQP_PROXY_USER = "amqp.proxy.username";
/**
* The AMQP proxy server password.
* Default value is {@code null}.
*/
public static final String AMQP_PROXY_PASSWORD = "amqp.proxy.password";
}
}