Skip to content

Commit 312142c

Browse files
author
Fernando Marino
committed
add proxy support for OIDC and gRPC transport
1 parent 1e0dbaa commit 312142c

14 files changed

Lines changed: 242 additions & 31 deletions

src/main/java/io/weaviate/client6/v1/api/Authentication.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,26 @@ public static Authentication resourceOwnerPassword(String username, String passw
5656
};
5757
}
5858

59+
/**
60+
* Authenticate using Resource Owner Password authorization grant with client secret.
61+
*
62+
* @param clientSecret Client secret.
63+
* @param username Resource owner username.
64+
* @param password Resource owner password.
65+
* @param scopes Client scopes.
66+
*
67+
* @return Authentication provider.
68+
* @throws WeaviateOAuthException if an error occurred at any point of the token
69+
* exchange process.
70+
*/
71+
public static Authentication resourceOwnerPassword(String clientSecret, String username, String password,
72+
List<String> scopes) {
73+
return transport -> {
74+
OidcConfig oidc = OidcUtils.getConfig(transport).withScopes(scopes).withScopes("offline_access");
75+
return TokenProvider.resourceOwnerPassword(oidc, clientSecret, username, password);
76+
};
77+
}
78+
5979
/**
6080
* Authenticate using Client Credentials authorization grant.
6181
*

src/main/java/io/weaviate/client6/v1/api/Config.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import io.weaviate.client6.v1.internal.BuildInfo;
1111
import io.weaviate.client6.v1.internal.ObjectBuilder;
12+
import io.weaviate.client6.v1.internal.Proxy;
1213
import io.weaviate.client6.v1.internal.Timeout;
1314
import io.weaviate.client6.v1.internal.TokenProvider;
1415
import io.weaviate.client6.v1.internal.grpc.GrpcChannelOptions;
@@ -23,7 +24,8 @@ public record Config(
2324
Map<String, String> headers,
2425
Authentication authentication,
2526
TrustManagerFactory trustManagerFactory,
26-
Timeout timeout) {
27+
Timeout timeout,
28+
Proxy proxy) {
2729

2830
public static Config of(Function<Custom, ObjectBuilder<Config>> fn) {
2931
return fn.apply(new Custom()).build();
@@ -39,23 +41,24 @@ private Config(Builder<?> builder) {
3941
builder.headers,
4042
builder.authentication,
4143
builder.trustManagerFactory,
42-
builder.timeout);
44+
builder.timeout,
45+
builder.proxy);
4346
}
4447

4548
RestTransportOptions restTransportOptions() {
4649
return restTransportOptions(null);
4750
}
4851

4952
RestTransportOptions restTransportOptions(TokenProvider tokenProvider) {
50-
return new RestTransportOptions(scheme, httpHost, httpPort, headers, tokenProvider, trustManagerFactory, timeout);
53+
return new RestTransportOptions(scheme, httpHost, httpPort, headers, tokenProvider, trustManagerFactory, timeout, proxy);
5154
}
5255

5356
GrpcChannelOptions grpcTransportOptions() {
5457
return grpcTransportOptions(null);
5558
}
5659

5760
GrpcChannelOptions grpcTransportOptions(TokenProvider tokenProvider) {
58-
return new GrpcChannelOptions(scheme, grpcHost, grpcPort, headers, tokenProvider, trustManagerFactory, timeout);
61+
return new GrpcChannelOptions(scheme, grpcHost, grpcPort, headers, tokenProvider, trustManagerFactory, timeout, proxy);
5962
}
6063

6164
private abstract static class Builder<SelfT extends Builder<SelfT>> implements ObjectBuilder<Config> {
@@ -69,6 +72,7 @@ private abstract static class Builder<SelfT extends Builder<SelfT>> implements O
6972
protected TrustManagerFactory trustManagerFactory;
7073
protected Timeout timeout = new Timeout();
7174
protected Map<String, String> headers = new HashMap<>();
75+
protected Proxy proxy;
7276

7377
/**
7478
* Set URL scheme. Subclasses may increase the visibility of this method to
@@ -174,6 +178,15 @@ public SelfT timeout(int initSeconds, int querySeconds, int insertSeconds) {
174178
return (SelfT) this;
175179
}
176180

181+
/**
182+
* Set proxy for all requests.
183+
*/
184+
@SuppressWarnings("unchecked")
185+
public SelfT proxy(Proxy proxy) {
186+
this.proxy = proxy;
187+
return (SelfT) this;
188+
}
189+
177190
/**
178191
* Weaviate will use the URL in this header to call Weaviate Embeddings
179192
* Service if an appropriate vectorizer is configured for collection.

src/main/java/io/weaviate/client6/v1/api/WeaviateClient.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@
2020
import io.weaviate.client6.v1.internal.rest.DefaultRestTransport;
2121
import io.weaviate.client6.v1.internal.rest.RestTransport;
2222
import io.weaviate.client6.v1.internal.rest.RestTransportOptions;
23+
import lombok.Getter;
2324

2425
public class WeaviateClient implements AutoCloseable {
2526
/** Store this for {@link #async()} helper. */
27+
@Getter
2628
private final Config config;
2729

2830
private final RestTransport restTransport;
@@ -63,14 +65,13 @@ public class WeaviateClient implements AutoCloseable {
6365
public final WeaviateClusterClient cluster;
6466

6567
public WeaviateClient(Config config) {
66-
RestTransportOptions restOpt;
68+
RestTransportOptions restOpt = config.restTransportOptions();
6769
GrpcChannelOptions grpcOpt;
6870
if (config.authentication() == null) {
69-
restOpt = config.restTransportOptions();
7071
grpcOpt = config.grpcTransportOptions();
7172
} else {
7273
TokenProvider tokenProvider;
73-
try (final var noAuthRest = new DefaultRestTransport(config.restTransportOptions())) {
74+
try (final var noAuthRest = new DefaultRestTransport(restOpt)) {
7475
tokenProvider = config.authentication().getTokenProvider(noAuthRest);
7576
} catch (Exception e) {
7677
// Generally exceptions are caught in TokenProvider internals.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package io.weaviate.client6.v1.internal;
2+
3+
import javax.annotation.Nullable;
4+
5+
public class Proxy {
6+
private final String host;
7+
private final int port;
8+
private final String scheme;
9+
private final String username;
10+
private final String password;
11+
12+
public Proxy(String host, int port, String scheme, @Nullable String username, @Nullable String password) {
13+
this.host = host;
14+
this.port = port;
15+
this.scheme = scheme;
16+
this.username = username;
17+
this.password = password;
18+
}
19+
20+
public Proxy(String host, int port) {
21+
this(host, port, "http", null, null);
22+
}
23+
24+
public String host() {
25+
return host;
26+
}
27+
28+
public int port() {
29+
return port;
30+
}
31+
32+
public String scheme() {
33+
return scheme;
34+
}
35+
36+
@Nullable
37+
public String username() {
38+
return username;
39+
}
40+
41+
@Nullable
42+
public String password() {
43+
return password;
44+
}
45+
}

src/main/java/io/weaviate/client6/v1/internal/TokenProvider.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,25 @@ public static TokenProvider resourceOwnerPassword(OidcConfig oidc, String userna
141141
return background(reuse(null, exchange(oidc, passwordGrant), DEFAULT_EARLY_EXPIRY));
142142
}
143143

144+
/**
145+
* Create a TokenProvider that uses Resource Owner Password authorization grant
146+
* with client secret.
147+
*
148+
* @param oidc OIDC config.
149+
* @param clientSecret Client secret.
150+
* @param username Resource owner username.
151+
* @param password Resource owner password.
152+
*
153+
* @return Internal TokenProvider implementation.
154+
* @throws WeaviateOAuthException if an error occurred at any point of the token
155+
* exchange process.
156+
*/
157+
public static TokenProvider resourceOwnerPassword(OidcConfig oidc, String clientSecret, String username,
158+
String password) {
159+
final var passwordGrant = NimbusTokenProvider.resourceOwnerPassword(oidc, clientSecret, username, password);
160+
return background(reuse(null, exchange(oidc, passwordGrant), DEFAULT_EARLY_EXPIRY));
161+
}
162+
144163
/**
145164
* Create a TokenProvider that uses Client Credentials authorization grant.
146165
*

src/main/java/io/weaviate/client6/v1/internal/TransportOptions.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,18 @@ public abstract class TransportOptions<H> {
1111
protected final H headers;
1212
protected final TrustManagerFactory trustManagerFactory;
1313
protected final Timeout timeout;
14+
protected final Proxy proxy;
1415

1516
protected TransportOptions(String scheme, String host, int port, H headers, TokenProvider tokenProvider,
16-
TrustManagerFactory tmf, Timeout timeout) {
17+
TrustManagerFactory tmf, Timeout timeout, Proxy proxy) {
1718
this.scheme = scheme;
1819
this.host = host;
1920
this.port = port;
2021
this.tokenProvider = tokenProvider;
2122
this.headers = headers;
2223
this.timeout = timeout;
2324
this.trustManagerFactory = tmf;
25+
this.proxy = proxy;
2426
}
2527

2628
public boolean isSecure() {
@@ -57,4 +59,9 @@ public H headers() {
5759
public TrustManagerFactory trustManagerFactory() {
5860
return this.trustManagerFactory;
5961
}
62+
63+
@Nullable
64+
public Proxy proxy() {
65+
return this.proxy;
66+
}
6067
}

src/main/java/io/weaviate/client6/v1/internal/grpc/DefaultGrpcTransport.java

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,9 @@
11
package io.weaviate.client6.v1.internal.grpc;
22

3-
import java.util.concurrent.CompletableFuture;
4-
import java.util.concurrent.TimeUnit;
5-
6-
import javax.net.ssl.SSLException;
7-
83
import com.google.common.util.concurrent.FutureCallback;
94
import com.google.common.util.concurrent.Futures;
105
import com.google.common.util.concurrent.ListenableFuture;
11-
6+
import io.grpc.HttpConnectProxiedSocketAddress;
127
import io.grpc.ManagedChannel;
138
import io.grpc.StatusRuntimeException;
149
import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts;
@@ -17,10 +12,17 @@
1712
import io.grpc.stub.AbstractStub;
1813
import io.grpc.stub.MetadataUtils;
1914
import io.weaviate.client6.v1.api.WeaviateApiException;
15+
import io.weaviate.client6.v1.internal.Proxy;
2016
import io.weaviate.client6.v1.internal.grpc.protocol.WeaviateGrpc;
2117
import io.weaviate.client6.v1.internal.grpc.protocol.WeaviateGrpc.WeaviateBlockingStub;
2218
import io.weaviate.client6.v1.internal.grpc.protocol.WeaviateGrpc.WeaviateFutureStub;
2319

20+
import javax.net.ssl.SSLException;
21+
import java.net.InetSocketAddress;
22+
import java.net.SocketAddress;
23+
import java.util.concurrent.CompletableFuture;
24+
import java.util.concurrent.TimeUnit;
25+
2426
public final class DefaultGrpcTransport implements GrpcTransport {
2527
private final ManagedChannel channel;
2628

@@ -88,7 +90,7 @@ public <RequestT, RequestM, ReplyM, ResponseT> CompletableFuture<ResponseT> perf
8890
var method = rpc.methodAsync();
8991
var stub = applyTimeout(futureStub, rpc);
9092
var reply = method.apply(stub, message);
91-
return toCompletableFuture(reply).thenApply(r -> rpc.unmarshal(r));
93+
return toCompletableFuture(reply).thenApply(rpc::unmarshal);
9294
}
9395

9496
/**
@@ -139,6 +141,27 @@ private static ManagedChannel buildChannel(GrpcChannelOptions transportOptions)
139141
channel.sslContext(sslCtx);
140142
}
141143

144+
if (transportOptions.proxy() != null) {
145+
Proxy proxy = transportOptions.proxy();
146+
if ("http".equals(proxy.scheme())) {
147+
final SocketAddress proxyAddress = new InetSocketAddress(proxy.host(), proxy.port());
148+
channel.proxyDetector(targetAddress -> {
149+
if (targetAddress instanceof InetSocketAddress) {
150+
HttpConnectProxiedSocketAddress.Builder builder = HttpConnectProxiedSocketAddress.newBuilder()
151+
.setProxyAddress(proxyAddress)
152+
.setTargetAddress((InetSocketAddress) targetAddress);
153+
154+
if (proxy.username() != null && proxy.password() != null) {
155+
builder.setUsername(proxy.username());
156+
builder.setPassword(proxy.password());
157+
}
158+
return builder.build();
159+
}
160+
return null;
161+
});
162+
}
163+
}
164+
142165
channel.intercept(MetadataUtils.newAttachHeadersInterceptor(transportOptions.headers()));
143166

144167
return channel.build();

src/main/java/io/weaviate/client6/v1/internal/grpc/GrpcChannelOptions.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import javax.net.ssl.TrustManagerFactory;
66

77
import io.grpc.Metadata;
8+
import io.weaviate.client6.v1.internal.Proxy;
89
import io.weaviate.client6.v1.internal.Timeout;
910
import io.weaviate.client6.v1.internal.TokenProvider;
1011
import io.weaviate.client6.v1.internal.TransportOptions;
@@ -13,19 +14,19 @@ public class GrpcChannelOptions extends TransportOptions<Metadata> {
1314
private final Integer maxMessageSize;
1415

1516
public GrpcChannelOptions(String scheme, String host, int port, Map<String, String> headers,
16-
TokenProvider tokenProvider, TrustManagerFactory tmf, Timeout timeout) {
17-
this(scheme, host, port, buildMetadata(headers), tokenProvider, tmf, null, timeout);
17+
TokenProvider tokenProvider, TrustManagerFactory tmf, Timeout timeout, Proxy proxy) {
18+
this(scheme, host, port, buildMetadata(headers), tokenProvider, tmf, null, timeout, proxy);
1819
}
1920

2021
private GrpcChannelOptions(String scheme, String host, int port, Metadata headers,
21-
TokenProvider tokenProvider, TrustManagerFactory tmf, Integer maxMessageSize, Timeout timeout) {
22-
super(scheme, host, port, headers, tokenProvider, tmf, timeout);
22+
TokenProvider tokenProvider, TrustManagerFactory tmf, Integer maxMessageSize, Timeout timeout, Proxy proxy) {
23+
super(scheme, host, port, headers, tokenProvider, tmf, timeout, proxy);
2324
this.maxMessageSize = maxMessageSize;
2425
}
2526

2627
public GrpcChannelOptions withMaxMessageSize(int maxMessageSize) {
2728
return new GrpcChannelOptions(scheme, host, port, headers, tokenProvider, trustManagerFactory, maxMessageSize,
28-
timeout);
29+
timeout, proxy);
2930
}
3031

3132
public Integer maxMessageSize() {

src/main/java/io/weaviate/client6/v1/internal/oidc/OidcConfig.java

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,32 @@
1111
public record OidcConfig(
1212
String clientId,
1313
String providerMetadata,
14-
Set<String> scopes) {
14+
Set<String> scopes,
15+
OidcProxy proxy) {
1516

16-
public OidcConfig(String clientId, String providerMetadata, Set<String> scopes) {
17+
public record OidcProxy(
18+
String host,
19+
int port,
20+
String scheme) {
21+
}
22+
23+
public OidcConfig(String clientId, String providerMetadata, Set<String> scopes, OidcProxy proxy) {
1724
this.clientId = clientId;
1825
this.providerMetadata = providerMetadata;
1926
this.scopes = scopes != null ? Set.copyOf(scopes) : Collections.emptySet();
27+
this.proxy = proxy;
28+
}
29+
30+
public OidcConfig(String clientId, String providerMetadata, Set<String> scopes) {
31+
this(clientId, providerMetadata, scopes, null);
2032
}
2133

2234
public OidcConfig(String clientId, String providerMetadata, List<String> scopes) {
23-
this(clientId, providerMetadata, scopes == null ? null : new HashSet<>(scopes));
35+
this(clientId, providerMetadata, scopes == null ? null : new HashSet<>(scopes), null);
36+
}
37+
38+
public OidcConfig(String clientId, String providerMetadata, List<String> scopes, OidcProxy proxy) {
39+
this(clientId, providerMetadata, scopes == null ? null : new HashSet<>(scopes), proxy);
2440
}
2541

2642
/** Create a new OIDC config with extended scopes. */
@@ -31,6 +47,6 @@ public OidcConfig withScopes(String... scopes) {
3147
/** Create a new OIDC config with extended scopes. */
3248
public OidcConfig withScopes(List<String> scopes) {
3349
var newScopes = Stream.concat(this.scopes.stream(), scopes.stream()).collect(Collectors.toSet());
34-
return new OidcConfig(clientId, providerMetadata, newScopes);
50+
return new OidcConfig(clientId, providerMetadata, newScopes, proxy);
3551
}
3652
}

0 commit comments

Comments
 (0)