-
Notifications
You must be signed in to change notification settings - Fork 125
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
215 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
168 changes: 168 additions & 0 deletions
168
src/main/java/org/codinjutsu/tools/jenkins/security/JenkinsConnectionSocketFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
package org.codinjutsu.tools.jenkins.security; | ||
|
||
import com.intellij.openapi.vfs.VfsUtil; | ||
import com.intellij.util.net.HttpConfigurable; | ||
import com.intellij.util.net.IdeaWideProxySelector; | ||
import org.apache.http.HttpHost; | ||
import org.apache.http.client.protocol.HttpClientContext; | ||
import org.apache.http.config.Registry; | ||
import org.apache.http.config.RegistryBuilder; | ||
import org.apache.http.conn.socket.ConnectionSocketFactory; | ||
import org.apache.http.conn.socket.PlainConnectionSocketFactory; | ||
import org.apache.http.conn.ssl.DefaultHostnameVerifier; | ||
import org.apache.http.conn.ssl.SSLConnectionSocketFactory; | ||
import org.apache.http.conn.util.PublicSuffixMatcherLoader; | ||
import org.apache.http.protocol.HttpContext; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.jetbrains.annotations.Nullable; | ||
|
||
import javax.net.ssl.HostnameVerifier; | ||
import javax.net.ssl.SSLContext; | ||
import java.io.IOException; | ||
import java.net.InetSocketAddress; | ||
import java.net.Proxy; | ||
import java.net.Socket; | ||
import java.net.URI; | ||
import java.util.Collections; | ||
import java.util.List; | ||
|
||
public class JenkinsConnectionSocketFactory { | ||
@NotNull | ||
public static final JenkinsConnectionSocketFactory INSTANCE = new JenkinsConnectionSocketFactory(); | ||
|
||
public @Nullable Registry<ConnectionSocketFactory> getRegistry(@NotNull String url, @NotNull SSLContext sslContext) { | ||
final Proxy proxy = getProxy(url); | ||
if(proxy.type() == Proxy.Type.SOCKS) { | ||
return createSocksRegistry(toUri(url), proxy, sslContext); | ||
} | ||
return createDefaultRegistry(sslContext); | ||
} | ||
|
||
@NotNull | ||
private static Registry<ConnectionSocketFactory> createDefaultRegistry(@NotNull SSLContext sslContext) { | ||
String[] supportedProtocols = null; | ||
String[] supportedCipherSuites = null; | ||
HostnameVerifier proxyAuthStrategyCopy = new DefaultHostnameVerifier(PublicSuffixMatcherLoader.getDefault()); | ||
final SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, | ||
supportedProtocols, supportedCipherSuites, proxyAuthStrategyCopy); | ||
|
||
return RegistryBuilder.<ConnectionSocketFactory>create() | ||
.register("http", PlainConnectionSocketFactory.getSocketFactory()) | ||
.register("https", sslConnectionSocketFactory) | ||
.build(); | ||
} | ||
|
||
public boolean prepareContext(@NotNull String url, | ||
@NotNull SSLContext sslContext, | ||
@NotNull HttpClientContext httpClientContext, | ||
@NotNull JenkinsDnsResolver dnsResolver) { | ||
httpClientContext.removeAttribute("http.socket-factory-registry"); | ||
dnsResolver.clearFakes(); | ||
final URI uri = toUri(url); | ||
final Proxy proxy = getProxy(uri); | ||
if(proxy.type() == Proxy.Type.SOCKS) { | ||
// see org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.SOCKET_FACTORY_REGISTRY | ||
httpClientContext.setAttribute("http.socket-factory-registry", getRegistry(url, sslContext)); | ||
if (uri != null) { | ||
dnsResolver.addFakeHost(uri.getHost()); | ||
} | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
private Registry<ConnectionSocketFactory> createSocksRegistry(@Nullable URI uri, | ||
@NotNull Proxy proxy, | ||
@NotNull SSLContext sslContext) { | ||
return RegistryBuilder.<ConnectionSocketFactory>create() | ||
.register("http", new SocksPlainConnectionSocketFactory(proxy)) | ||
.register("https", new SocksSSLConnectionSocketFactory(uri != null ? uri.getHost() : null, sslContext, proxy)) | ||
.build(); | ||
} | ||
|
||
@NotNull | ||
private static HttpConfigurable getHttpConfigurable() { | ||
return HttpConfigurable.getInstance(); | ||
} | ||
|
||
private static @NotNull Proxy getProxy(String url) { | ||
return getProxy(toUri(url)); | ||
} | ||
|
||
private static @NotNull Proxy getProxy(@Nullable URI uri) { | ||
final List<Proxy> proxies = uri == null ? Collections.emptyList() : | ||
new IdeaWideProxySelector(getHttpConfigurable()).select(uri); | ||
return proxies.isEmpty() ? Proxy.NO_PROXY : proxies.get(0); | ||
} | ||
|
||
@Nullable | ||
private static URI toUri(String url) { | ||
return url != null ? VfsUtil.toUri(url) : null; | ||
} | ||
|
||
|
||
private static final class SocksPlainConnectionSocketFactory extends PlainConnectionSocketFactory { | ||
@NotNull | ||
private final Proxy proxy; | ||
|
||
public SocksPlainConnectionSocketFactory(@NotNull Proxy proxy) { | ||
super(); | ||
this.proxy = proxy; | ||
} | ||
|
||
@NotNull | ||
public Proxy getProxy() { | ||
return this.proxy; | ||
} | ||
|
||
@NotNull | ||
public Socket createSocket(@Nullable HttpContext context) { | ||
return new Socket(this.proxy); | ||
} | ||
|
||
@NotNull | ||
public Socket connectSocket(int connectTimeout, | ||
@Nullable Socket socket, | ||
@NotNull HttpHost host, | ||
@NotNull InetSocketAddress remoteAddress, | ||
@Nullable InetSocketAddress localAddress, | ||
@Nullable HttpContext context) throws IOException { | ||
InetSocketAddress unresolvedRemote = InetSocketAddress.createUnresolved(host.getHostName(), remoteAddress.getPort()); | ||
return super.connectSocket(connectTimeout, socket, host, unresolvedRemote, localAddress, context); | ||
} | ||
} | ||
|
||
private static final class SocksSSLConnectionSocketFactory extends SSLConnectionSocketFactory { | ||
@Nullable | ||
private final String host; | ||
@NotNull | ||
private final Proxy proxy; | ||
|
||
public SocksSSLConnectionSocketFactory(@Nullable String host, @NotNull SSLContext sslContext, @NotNull Proxy proxy) { | ||
super(sslContext); | ||
this.host = host; | ||
this.proxy = proxy; | ||
} | ||
|
||
@NotNull | ||
public Proxy getProxy() { | ||
return this.proxy; | ||
} | ||
|
||
@NotNull | ||
public Socket createSocket(@NotNull HttpContext context) { | ||
return new Socket(this.proxy); | ||
} | ||
|
||
@NotNull | ||
public Socket connectSocket(int connectTimeout, | ||
@Nullable Socket socket, | ||
@NotNull HttpHost host, | ||
@NotNull InetSocketAddress remoteAddress, | ||
@Nullable InetSocketAddress localAddress, | ||
@Nullable HttpContext context) throws IOException { | ||
final var unresolvedRemote = InetSocketAddress.createUnresolved(host.getHostName(), remoteAddress.getPort()); | ||
return super.connectSocket(connectTimeout, socket, host, unresolvedRemote, localAddress, context); | ||
} | ||
} | ||
} |
33 changes: 33 additions & 0 deletions
33
src/main/java/org/codinjutsu/tools/jenkins/security/JenkinsDnsResolver.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package org.codinjutsu.tools.jenkins.security; | ||
|
||
import org.apache.http.conn.DnsResolver; | ||
import org.apache.http.impl.conn.SystemDefaultDnsResolver; | ||
import org.jetbrains.annotations.NotNull; | ||
|
||
import java.net.InetAddress; | ||
import java.net.UnknownHostException; | ||
import java.util.HashSet; | ||
import java.util.Set; | ||
|
||
public class JenkinsDnsResolver implements DnsResolver { | ||
private static final DnsResolver DNS_RESOLVER = SystemDefaultDnsResolver.INSTANCE; | ||
private final Set<String> hostWithFakeDns = new HashSet<>(); | ||
|
||
public void clearFakes() { | ||
hostWithFakeDns.clear(); | ||
} | ||
|
||
public void addFakeHost(String host) { | ||
hostWithFakeDns.add(host); | ||
} | ||
|
||
@Override | ||
public InetAddress[] resolve(@NotNull String host) throws UnknownHostException { | ||
return hostWithFakeDns.contains(host) ? returnFakeDns(): DNS_RESOLVER.resolve(host); | ||
} | ||
|
||
private InetAddress[] returnFakeDns() throws UnknownHostException { | ||
final var fakeIp = new byte[]{1, 1, 1, 1}; | ||
return new InetAddress[]{InetAddress.getByAddress(fakeIp)}; | ||
} | ||
} |