Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public final class ProxyConfiguration implements ToCopyableBuilder<ProxyConfigur
private final int port;
private final String username;
private final String password;
private final ProxyAuthScheme proxyAuthScheme;
private final Set<String> nonProxyHosts;

private ProxyConfiguration(BuilderImpl builder) {
Expand All @@ -56,6 +57,7 @@ private ProxyConfiguration(BuilderImpl builder) {
this.port = resolvePort(builder, proxyConfigProvider);
this.username = resolveUserName(builder, proxyConfigProvider);
this.password = resolvePassword(builder, proxyConfigProvider);
this.proxyAuthScheme = builder.proxyAuthScheme;
this.nonProxyHosts = resolveNonProxyHosts(builder, proxyConfigProvider);
}

Expand Down Expand Up @@ -151,6 +153,13 @@ public Set<String> nonProxyHosts() {
return Collections.unmodifiableSet(nonProxyHosts != null ? nonProxyHosts : Collections.emptySet());
}

/**
* @return The auth scheme to use to authenticate with the proxy.
*/
public ProxyAuthScheme proxyAuthScheme() {
return proxyAuthScheme;
}

@Override
public boolean equals(Object o) {
if (this == o) {
Expand Down Expand Up @@ -183,6 +192,10 @@ public boolean equals(Object o) {
return false;
}

if (proxyAuthScheme != null ? !proxyAuthScheme.equals(that.proxyAuthScheme) : that.proxyAuthScheme != null) {
return false;
}

return nonProxyHosts.equals(that.nonProxyHosts);

}
Expand All @@ -195,6 +208,7 @@ public int hashCode() {
result = 31 * result + nonProxyHosts.hashCode();
result = 31 * result + (username != null ? username.hashCode() : 0);
result = 31 * result + (password != null ? password.hashCode() : 0);
result = 31 * result + (proxyAuthScheme != null ? proxyAuthScheme.hashCode() : 0);
return result;
}

Expand Down Expand Up @@ -243,6 +257,17 @@ public interface Builder extends CopyableBuilder<Builder, ProxyConfiguration> {
*/
Builder nonProxyHosts(Set<String> nonProxyHosts);

/**
* Configure the auth scheme to use to authenticate with the proxy.
* <p>
* If unset and {@link #username(String)} and {@link #password(String)} are set, the client will
* assume {@link ProxyAuthScheme#BASIC} auth.
*
* @param proxyAuthScheme The auth scheme.
* @return This object for method chaining.
*/
Builder proxyAuthScheme(ProxyAuthScheme proxyAuthScheme);

/**
* Set the username used to authenticate with the proxy username.
*
Expand Down Expand Up @@ -293,6 +318,7 @@ private static final class BuilderImpl implements Builder {
private String scheme = "http";
private String host;
private int port = 0;
private ProxyAuthScheme proxyAuthScheme;
private String username;
private String password;
private Set<String> nonProxyHosts;
Expand All @@ -310,6 +336,7 @@ private BuilderImpl(ProxyConfiguration proxyConfiguration) {
this.port = proxyConfiguration.port;
this.nonProxyHosts = proxyConfiguration.nonProxyHosts != null ?
new HashSet<>(proxyConfiguration.nonProxyHosts) : null;
this.proxyAuthScheme = proxyConfiguration.proxyAuthScheme;
this.username = proxyConfiguration.username;
this.password = proxyConfiguration.password;
}
Expand Down Expand Up @@ -342,6 +369,12 @@ public Builder nonProxyHosts(Set<String> nonProxyHosts) {
return this;
}

@Override
public Builder proxyAuthScheme(ProxyAuthScheme proxyAuthScheme) {
this.proxyAuthScheme = proxyAuthScheme;
return this;
}

@Override
public Builder username(String username) {
this.username = username;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import javax.security.auth.login.Configuration;
import software.amazon.awssdk.annotations.SdkInternalApi;
import software.amazon.awssdk.annotations.SdkTestInternalApi;
import software.amazon.awssdk.http.Protocol;
import software.amazon.awssdk.http.ProtocolNegotiation;
import software.amazon.awssdk.http.nio.netty.ProxyAuthScheme;
import software.amazon.awssdk.http.nio.netty.ProxyConfiguration;
import software.amazon.awssdk.http.nio.netty.SdkEventLoopGroup;
import software.amazon.awssdk.http.nio.netty.internal.http2.HttpOrHttp2ChannelPool;
Expand Down Expand Up @@ -88,6 +90,8 @@ public void channelCreated(Channel ch) throws Exception {
private final SslContextProvider sslContextProvider;
private final Boolean useNonBlockingDnsResolver;

private final Configuration negotiateAuthConfig;

private AwaitCloseChannelPoolMap(Builder builder, Function<Builder, BootstrapProvider> createBootStrapProvider) {
this.configuration = builder.configuration;
this.protocol = builder.protocol;
Expand All @@ -100,6 +104,7 @@ private AwaitCloseChannelPoolMap(Builder builder, Function<Builder, BootstrapPro
this.bootstrapProvider = createBootStrapProvider.apply(builder);
this.sslContextProvider = new SslContextProvider(configuration, protocol, protocolNegotiation, sslProvider);
this.useNonBlockingDnsResolver = builder.useNonBlockingDnsResolver;
this.negotiateAuthConfig = builder.negotiateAuthConfig;
}

private AwaitCloseChannelPoolMap(Builder builder) {
Expand Down Expand Up @@ -158,6 +163,26 @@ protected SimpleChannelPoolAwareChannelPool newPool(URI key) {
}

private ProxyAuthGenerator resolveProxyAuthGenerator(ProxyConfiguration proxyConfiguration) {
ProxyAuthScheme proxyAuthScheme = proxyConfiguration.proxyAuthScheme();

if (proxyAuthScheme != null) {
switch (proxyAuthScheme) {
case NEGOTIATE:
return new NegotiateProxyAuthGenerator(negotiateAuthConfig);
case BASIC: {
String username = proxyConfiguration.username();
String password = proxyConfiguration.password();
if (!StringUtils.isEmpty(username) && !StringUtils.isEmpty(password)) {
return new BasicProxyAuthGenerator(username, password);
}
throw new IllegalArgumentException("username and password must be configured when using BASIC proxy auth");
}
default:
throw new RuntimeException("Unknown proxy auth scheme: " + proxyAuthScheme);
}
}

// for back-compat, BASIC if scheme not configured but username password are set
String username = proxyConfiguration.username();
String password = proxyConfiguration.password();
if (!StringUtils.isEmpty(username) && !StringUtils.isEmpty(password)) {
Expand Down Expand Up @@ -304,6 +329,9 @@ public static class Builder {
private ProxyConfiguration proxyConfiguration;
private Boolean useNonBlockingDnsResolver;

// testing only
private Configuration negotiateAuthConfig;

private Builder() {
}

Expand Down Expand Up @@ -362,6 +390,12 @@ public Builder useNonBlockingDnsResolver(Boolean useNonBlockingDnsResolver) {
return this;
}

@SdkTestInternalApi
public Builder negotiateAuthConfig(Configuration negotiateAuthConfig) {
this.negotiateAuthConfig = negotiateAuthConfig;
return this;
}

public AwaitCloseChannelPoolMap build() {
return new AwaitCloseChannelPoolMap(this);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import org.ietf.jgss.GSSName;
import org.ietf.jgss.Oid;
import software.amazon.awssdk.annotations.SdkInternalApi;
import software.amazon.awssdk.annotations.SdkTestInternalApi;
import software.amazon.awssdk.http.nio.netty.ProxyAuthScheme;
import software.amazon.awssdk.utils.BinaryUtils;

Expand All @@ -52,9 +51,12 @@ public NegotiateProxyAuthGenerator() {
this(createDefaultConfig());
}

@SdkTestInternalApi
NegotiateProxyAuthGenerator(Configuration config) {
this.config = config;
public NegotiateProxyAuthGenerator(Configuration config) {
if (config != null) {
this.config = config;
} else {
this.config = createDefaultConfig();
}
}

@Override
Expand All @@ -69,8 +71,12 @@ public String generateAuthParams(URI proxyEndpoint) {

byte[] token = Subject.doAs(subject, (PrivilegedExceptionAction<byte[]>) () -> {
GSSContext ctx = createGssContext(getManager(), proxyEndpoint);
ctx.requestMutualAuth(true);
return ctx.initSecContext(new byte[0], 0, 0);
try {
ctx.requestMutualAuth(true);
return ctx.initSecContext(new byte[0], 0, 0);
} finally {
ctx.dispose();
}
});

return BinaryUtils.toBase64(token);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public ProxyTunnelInitHandler(ChannelPool sourcePool, URI proxyAddress, String p
this.proxyAddress = proxyAddress;
this.remoteHost = remoteHost;
this.initPromise = initPromise;
if (!StringUtils.isBlank(proxyPassword) && !StringUtils.isBlank(proxyPassword)) {
if (!StringUtils.isBlank(proxyUsername) && !StringUtils.isBlank(proxyPassword)) {
this.authGenerator = new BasicProxyAuthGenerator(proxyUsername, proxyPassword);
} else {
this.authGenerator = null;
Expand All @@ -94,7 +94,15 @@ public ProxyTunnelInitHandler(ChannelPool sourcePool, URI proxyAddress, ProxyAut
public void handlerAdded(ChannelHandlerContext ctx) {
ChannelPipeline pipeline = ctx.pipeline();
pipeline.addBefore(ctx.name(), null, httpCodecSupplier.get());
HttpRequest connectRequest = connectRequest();

HttpRequest connectRequest;
try {
connectRequest = connectRequest();
} catch (Throwable t) {
handleConnectRequestFailure(ctx, t);
return;
}

ctx.channel().writeAndFlush(connectRequest).addListener(f -> {
if (!f.isSuccess()) {
handleConnectRequestFailure(ctx, f.cause());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,11 @@ private void setRandomValue(Object o, Method setter) throws InvocationTargetExce
setter.invoke(o, randomSet());
} else if (Boolean.class.equals(paramClass)) {
setter.invoke(o, RNG.nextBoolean());
} else {
} else if (ProxyAuthScheme.class.equals(paramClass)) {
ProxyAuthScheme authScheme = ProxyAuthScheme.values()[RNG.nextInt(ProxyAuthScheme.values().length)];
setter.invoke(o, authScheme);
}
else {
throw new RuntimeException("Don't know how create random value for type " + paramClass);
}
}
Expand Down
Loading
Loading