package hudson.plugins.tfs.model;
import hudson.ProxyConfiguration;
import hudson.util.Secret;
import org.apache.commons.lang.StringUtils;
import java.io.Serializable;
import java.net.Authenticator;
import java.net.InetSocketAddress;
import java.net.PasswordAuthentication;
import java.net.Proxy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;
/**
* A {@link Serializable} adapter between {@link ProxyConfiguration} and {@link ProxyHostEx}.
*/
public class WebProxySettings implements Serializable {
private static final long serialVersionUID = 401L;
private final String hostName;
private final int port;
private final String proxyUser;
private final Secret proxySecret;
private final List<Pattern> noProxyHostPatterns;
@SuppressWarnings("unused" /* Needed by Serializable interface */)
private WebProxySettings() {
this(null, -1, null, null, null);
}
/**
* Convenience constructor, mostly for tests.
*
* @param hostName the name (or address) of the proxy server.
* May be {@code null}, meaning there is no proxy server configured.
* @param port the port that the proxy server is listening on
* @param noProxyHostPatterns a list of {@link Pattern} representing hosts that should not be proxied.
* May be {@code null}, meaning all hosts will be proxied.
* @param proxyUser the name of the user with which to authenticate to the proxy server.
* May be {@code null}, meaning the proxy server doesn't need authentication.
* @param proxySecret the password of the user with which to authenticate to the proxy server.
* May be {@code null}, meaning the proxy server doesn't need authentication.
*/
public WebProxySettings(final String hostName, final int port, final List<Pattern> noProxyHostPatterns, final String proxyUser, final Secret proxySecret) {
this.hostName = hostName;
this.port = port;
this.noProxyHostPatterns = copyNoProxyHostPatterns(noProxyHostPatterns);
this.proxyUser = proxyUser;
this.proxySecret = proxySecret;
}
/**
* Initialize a {@link WebProxySettings} from a Jenkins {@link ProxyConfiguration}.
*
* @param proxyConfiguration the proxy settings as obtained from Jenkins.
* May be {@code null}, meaning there is no proxy configured.
*/
public WebProxySettings(final ProxyConfiguration proxyConfiguration) {
if (proxyConfiguration != null) {
this.hostName = proxyConfiguration.name;
this.port = proxyConfiguration.port;
this.proxyUser = proxyConfiguration.getUserName();
this.noProxyHostPatterns = copyNoProxyHostPatterns(proxyConfiguration.getNoProxyHostPatterns());
this.proxySecret = Secret.fromString(proxyConfiguration.getEncryptedPassword());
}
else {
this.hostName = null;
this.port = -1;
this.proxyUser = null;
this.proxySecret = null;
this.noProxyHostPatterns = copyNoProxyHostPatterns(null);
}
}
private static ArrayList<Pattern> copyNoProxyHostPatterns(final List<Pattern> noProxyHostPatterns) {
return new ArrayList<Pattern>(
noProxyHostPatterns == null
? Collections.<Pattern>emptyList()
: noProxyHostPatterns
);
}
/**
* Initialize a {@link ProxyHostEx} from this {@link WebProxySettings} for the provided hostToProxy.
* May return null, which either means there is no proxy server configured or it does not apply
* to the provided hostToProxy.
*
* @param hostToProxy the name of the host for which proxying is considered.
* @return an instance of {@link ProxyHostEx} or {@code null} if no proxy is to be used.
*/
public ProxyHostEx toProxyHost(final String hostToProxy) {
final ProxyHostEx proxyHost;
if (this.hostName != null) {
final boolean shouldProxy = shouldProxy(hostToProxy, noProxyHostPatterns);
if (shouldProxy) {
proxyHost = new ProxyHostEx(hostName, port, proxyUser, proxySecret);
} else {
proxyHost = null;
}
}
else {
proxyHost = null;
}
return proxyHost;
}
public Proxy toProxy(final String hostToProxy) {
final Proxy proxy;
if (this.hostName != null) {
final boolean shouldProxy = shouldProxy(hostToProxy, noProxyHostPatterns);
if (shouldProxy) {
final InetSocketAddress proxyAddress = new InetSocketAddress(hostName, port);
proxy = new Proxy(Proxy.Type.HTTP, proxyAddress);
if (proxyUser != null && proxySecret != null) {
final Authenticator authenticator = new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
if (StringUtils.equalsIgnoreCase(hostName, this.getRequestingHost())) {
return new PasswordAuthentication(proxyUser, proxySecret.getPlainText().toCharArray());
}
return null;
}
};
Authenticator.setDefault(authenticator);
}
}
else {
proxy = Proxy.NO_PROXY;
}
}
else {
proxy = Proxy.NO_PROXY;
}
return proxy;
}
static boolean shouldProxy(final String host, final List<Pattern> noProxyHostPatterns) {
// inspired by https://github.com/jenkinsci/git-client-plugin/commit/2fefeae06db79d09d6604994001f8f2bd21549e1
boolean shouldProxy = true;
for (final Pattern p : noProxyHostPatterns) {
if (p.matcher(host).matches()) {
shouldProxy = false;
break;
}
}
return shouldProxy;
}
public String getHostName() {
return hostName;
}
public int getPort() {
return port;
}
public String getProxyUser() {
return proxyUser;
}
public Secret getProxySecret() {
return proxySecret;
}
}