Skip to content

Commit 95e016f

Browse files
committed
Refactor GrpcClient auth logic into new AuthProvider interface
Previously two separate interfaces were used
1 parent 0bd3d02 commit 95e016f

2 files changed

Lines changed: 58 additions & 25 deletions

File tree

src/main/java/com/ibm/etcd/client/EtcdClient.java

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
import java.util.concurrent.TimeUnit;
3636
import java.util.concurrent.atomic.AtomicInteger;
3737
import java.util.function.Consumer;
38-
import java.util.function.Supplier;
3938

4039
import javax.net.ssl.SSLException;
4140
import javax.net.ssl.TrustManagerFactory;
@@ -52,6 +51,7 @@
5251
import com.ibm.etcd.api.AuthGrpc;
5352
import com.ibm.etcd.api.AuthenticateRequest;
5453
import com.ibm.etcd.api.AuthenticateResponse;
54+
import com.ibm.etcd.client.GrpcClient.AuthProvider;
5555
import com.ibm.etcd.client.kv.EtcdKvClient;
5656
import com.ibm.etcd.client.kv.KvClient;
5757
import com.ibm.etcd.client.lease.EtcdLeaseClient;
@@ -283,14 +283,22 @@ public static Builder forEndpoints(String endpoints) {
283283

284284
this.channel = chanBuilder.build();
285285

286-
Predicate<Throwable> rr = name != null ? EtcdClient::reauthRequired : null;
287-
Supplier<CallCredentials> rc = name != null ? this::refreshCredentials : null;
286+
AuthProvider authProvider = name == null ? null : new AuthProvider() {
287+
@Override
288+
public boolean requiresReauth(Throwable t) {
289+
return EtcdClient.reauthRequired(t);
290+
}
291+
@Override
292+
public CallCredentials refreshCredentials() {
293+
return EtcdClient.this.refreshCredentials();
294+
}
295+
};
288296

289297
this.sharedInternalExecutor = new SharedScheduledExecutorService(internalExecutor);
290-
this.grpc = new GrpcClient(channel, rr, rc, sharedInternalExecutor,
298+
this.grpc = new GrpcClient(channel, authProvider, sharedInternalExecutor,
291299
() -> Thread.currentThread() instanceof EtcdEventThread,
292300
userExecutor, sendViaEventLoop, defaultTimeoutMs);
293-
if (initialAuth) {
301+
if (authProvider != null && initialAuth) {
294302
grpc.authenticateNow();
295303
}
296304

src/main/java/com/ibm/etcd/client/GrpcClient.java

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,18 @@ public class GrpcClient {
7373
private static final Logger logger = LoggerFactory.getLogger(GrpcClient.class);
7474

7575
private final long defaultTimeoutMs;
76+
77+
public interface AuthProvider {
78+
CallCredentials refreshCredentials();
79+
boolean requiresReauth(Throwable t);
80+
}
81+
82+
private static final AuthProvider NO_AUTH = new AuthProvider() {
83+
@Override public boolean requiresReauth(Throwable t) { return false; }
84+
@Override public CallCredentials refreshCredentials() { throw new IllegalStateException(); }
85+
};
7686

77-
//TODO maybe combine these into an auth provider intface
78-
private final Supplier<CallCredentials> refreshCreds;
79-
private final Predicate<Throwable> reauthRequired;
87+
private final AuthProvider authProvider;
8088

8189
private final ManagedChannel channel;
8290

@@ -98,18 +106,37 @@ public class GrpcClient {
98106
// modified only by reauthenticate() method
99107
private CallOptions callOptions = CallOptions.DEFAULT; // volatile tbd - lazy probably ok
100108

101-
102-
//TODO whether some/all of the channel construction is moved in here
109+
/**
110+
* @deprecated use other constructor
111+
*/
112+
@Deprecated
103113
public GrpcClient(ManagedChannel channel,
104114
Predicate<Throwable> reauthRequired,
105115
Supplier<CallCredentials> credsSupplier,
106116
ScheduledExecutorService executor, Condition isEventThread,
107117
Executor userExecutor, boolean sendViaEventLoop, long defaultTimeoutMs) {
108-
Preconditions.checkArgument((reauthRequired == null) == (credsSupplier == null),
109-
"must supply both or neither reauth and creds");
118+
this(channel, reauthRequired == null ? null : new AuthProvider() {
119+
{
120+
Preconditions.checkArgument((reauthRequired == null) == (credsSupplier == null),
121+
"must supply both or neither reauth and creds");
122+
}
123+
@Override
124+
public boolean requiresReauth(Throwable t) {
125+
return reauthRequired.apply(t);
126+
}
127+
@Override
128+
public CallCredentials refreshCredentials() {
129+
return credsSupplier.get();
130+
}
131+
}, executor, isEventThread, userExecutor, sendViaEventLoop, defaultTimeoutMs);
132+
}
133+
134+
//TODO whether some/all of the channel construction is moved in here
135+
public GrpcClient(ManagedChannel channel, AuthProvider authProvider,
136+
ScheduledExecutorService executor, Condition isEventThread,
137+
Executor userExecutor, boolean sendViaEventLoop, long defaultTimeoutMs) {
110138
this.channel = channel;
111-
this.refreshCreds = credsSupplier;
112-
this.reauthRequired = reauthRequired;
139+
this.authProvider = authProvider != null ? authProvider : NO_AUTH;
113140
this.ses = MoreExecutors.listeningDecorator(executor);
114141
this.isEventThread = isEventThread;
115142
this.userExecutor = userExecutor;
@@ -138,9 +165,8 @@ public Executor getResponseExecutor() {
138165
}
139166

140167
public void authenticateNow() {
141-
if (refreshCreds != null) {
142-
reauthenticate(getCallOptions());
143-
}
168+
assert authProvider != NO_AUTH;
169+
reauthenticate(getCallOptions());
144170
}
145171

146172
protected CallOptions getCallOptions() {
@@ -298,11 +324,11 @@ protected static boolean causedByJavaError(Throwable t) {
298324
* @return true if reauthentication was required and attempted
299325
*/
300326
protected boolean reauthIfRequired(Throwable error, CallOptions callOpts) {
301-
if (reauthRequired == null || !reauthRequired.apply(error)) {
302-
return false;
327+
if (authProvider.requiresReauth(error)) {
328+
reauthenticate(callOpts);
329+
return true;
303330
}
304-
reauthenticate(callOpts);
305-
return true;
331+
return false;
306332
}
307333

308334
public static boolean isConnectException(Throwable t) {
@@ -321,7 +347,7 @@ private void reauthenticate(CallOptions failedOpts) {
321347
synchronized (this) {
322348
CallOptions callOpts = getCallOptions();
323349
if (callOpts == failedOpts) {
324-
callOptions = callOpts.withCallCredentials(refreshCreds.get());
350+
callOptions = callOpts.withCallCredentials(authProvider.refreshCredentials());
325351
}
326352
}
327353
}
@@ -335,7 +361,7 @@ public <ReqT,RespT> StreamObserver<ReqT> callStream(MethodDescriptor<ReqT,RespT>
335361
public <ReqT,RespT> StreamObserver<ReqT> callStream(MethodDescriptor<ReqT,RespT> method,
336362
ResilientResponseObserver<ReqT,RespT> respStream, Executor responseExecutor) {
337363
// must explicitly auth in stream case to ensure unauthenticated version isn't used
338-
if (refreshCreds != null && getCallOptions() == CallOptions.DEFAULT) {
364+
if (authProvider != NO_AUTH && getCallOptions() == CallOptions.DEFAULT) {
339365
// This will update callOptions with new CallCredentials prior to opening the stream
340366
authenticateNow();
341367
}
@@ -551,8 +577,7 @@ private void onFinish(Throwable err) {
551577
// is required - instead just cancel the "current"
552578
// stream which will cause the top-level stream
553579
// to be refreshed after a reauth is done
554-
if (err == null || reauthRequired == null
555-
|| !reauthRequired.apply(err)) {
580+
if (err == null || !authProvider.requiresReauth(err)) {
556581
error = err;
557582
finished = true;
558583
}

0 commit comments

Comments
 (0)