Skip to content

Commit 861f914

Browse files
authored
core: add CallCredentials2 and deprecate CallCredentials' old interface (#4902)
This is the first step of smoothly changing the CallCredentials API. Security level and authority are parameters required to be passed to applyRequestMetadata(). This change wraps them, along with MethodDescriptor and the transport attributes to RequestInfo, which is more clear to the implementers. ATTR_SECURITY_LEVEL is moved to the internal GrpcAttributes and annotated as TransportAttr, because transports are required to set it, but no user is actually reading them from {Client,Server}Call.getAttributes(). ATTR_AUTHORITY is removed, because no transport is overriding it. All involved interfaces are changed to abstract classes, as this will make further API changes smoother. The CallCredentials name is stabilized, thus we first introduce CallCredentials2, ask CallCredentials implementations to migrate to it, while GRPC accepting both at the same time, then replace CallCredentials with CallCredentials2.
1 parent 4ce9c04 commit 861f914

File tree

16 files changed

+514
-94
lines changed

16 files changed

+514
-94
lines changed

auth/src/main/java/io/grpc/auth/GoogleAuthLibraryCallCredentials.java

+7-14
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@
2222
import com.google.auth.RequestMetadataCallback;
2323
import com.google.common.annotations.VisibleForTesting;
2424
import com.google.common.io.BaseEncoding;
25-
import io.grpc.Attributes;
26-
import io.grpc.CallCredentials;
25+
import io.grpc.CallCredentials2;
2726
import io.grpc.Metadata;
2827
import io.grpc.MethodDescriptor;
2928
import io.grpc.SecurityLevel;
@@ -47,7 +46,7 @@
4746
/**
4847
* Wraps {@link Credentials} as a {@link CallCredentials}.
4948
*/
50-
final class GoogleAuthLibraryCallCredentials implements CallCredentials {
49+
final class GoogleAuthLibraryCallCredentials extends CallCredentials2 {
5150
private static final Logger log
5251
= Logger.getLogger(GoogleAuthLibraryCallCredentials.class.getName());
5352
private static final JwtHelper jwtHelper
@@ -88,26 +87,20 @@ public GoogleAuthLibraryCallCredentials(Credentials creds) {
8887
public void thisUsesUnstableApi() {}
8988

9089
@Override
91-
public void applyRequestMetadata(MethodDescriptor<?, ?> method, Attributes attrs,
92-
Executor appExecutor, final MetadataApplier applier) {
93-
SecurityLevel security = attrs.get(ATTR_SECURITY_LEVEL);
94-
if (security == null) {
95-
// Although the API says ATTR_SECURITY_LEVEL is required, no one was really looking at it thus
96-
// there may be transports that got away without setting it. Now we start to check it, it'd
97-
// be less disruptive to tolerate nulls.
98-
security = SecurityLevel.NONE;
99-
}
90+
public void applyRequestMetadata(
91+
RequestInfo info, Executor appExecutor, final MetadataApplier applier) {
92+
SecurityLevel security = info.getSecurityLevel();
10093
if (requirePrivacy && security != SecurityLevel.PRIVACY_AND_INTEGRITY) {
10194
applier.fail(Status.UNAUTHENTICATED
10295
.withDescription("Credentials require channel with PRIVACY_AND_INTEGRITY security level. "
10396
+ "Observed security level: " + security));
10497
return;
10598
}
10699

107-
String authority = checkNotNull(attrs.get(ATTR_AUTHORITY), "authority");
100+
String authority = checkNotNull(info.getAuthority(), "authority");
108101
final URI uri;
109102
try {
110-
uri = serviceUri(authority, method);
103+
uri = serviceUri(authority, info.getMethodDescriptor());
111104
} catch (StatusException e) {
112105
applier.fail(e.getStatus());
113106
return;

auth/src/test/java/io/grpc/auth/GoogleAuthLibraryCallCredentialsTest.java

+63-59
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@
3939
import com.google.common.collect.ListMultimap;
4040
import com.google.common.collect.Multimaps;
4141
import io.grpc.Attributes;
42-
import io.grpc.CallCredentials;
4342
import io.grpc.CallCredentials.MetadataApplier;
43+
import io.grpc.CallCredentials2;
4444
import io.grpc.Metadata;
4545
import io.grpc.MethodDescriptor;
4646
import io.grpc.SecurityLevel;
@@ -105,11 +105,8 @@ public class GoogleAuthLibraryCallCredentialsTest {
105105
.build();
106106
private URI expectedUri = URI.create("https://testauthority/a.service");
107107

108-
private final String authority = "testauthority";
109-
private final Attributes attrs = Attributes.newBuilder()
110-
.set(CallCredentials.ATTR_AUTHORITY, authority)
111-
.set(CallCredentials.ATTR_SECURITY_LEVEL, SecurityLevel.PRIVACY_AND_INTEGRITY)
112-
.build();
108+
private static final String AUTHORITY = "testauthority";
109+
private static final SecurityLevel SECURITY_LEVEL = SecurityLevel.PRIVACY_AND_INTEGRITY;
113110

114111
private ArrayList<Runnable> pendingRunnables = new ArrayList<>();
115112

@@ -155,7 +152,7 @@ public void copyCredentialsToHeaders() throws Exception {
155152

156153
GoogleAuthLibraryCallCredentials callCredentials =
157154
new GoogleAuthLibraryCallCredentials(credentials);
158-
callCredentials.applyRequestMetadata(method, attrs, executor, applier);
155+
callCredentials.applyRequestMetadata(new RequestInfoImpl(), executor, applier);
159156

160157
verify(credentials).getRequestMetadata(eq(expectedUri));
161158
verify(applier).apply(headersCaptor.capture());
@@ -177,7 +174,7 @@ public void invalidBase64() throws Exception {
177174

178175
GoogleAuthLibraryCallCredentials callCredentials =
179176
new GoogleAuthLibraryCallCredentials(credentials);
180-
callCredentials.applyRequestMetadata(method, attrs, executor, applier);
177+
callCredentials.applyRequestMetadata(new RequestInfoImpl(), executor, applier);
181178

182179
verify(credentials).getRequestMetadata(eq(expectedUri));
183180
verify(applier).fail(statusCaptor.capture());
@@ -193,7 +190,7 @@ public void credentialsFailsWithIoException() throws Exception {
193190

194191
GoogleAuthLibraryCallCredentials callCredentials =
195192
new GoogleAuthLibraryCallCredentials(credentials);
196-
callCredentials.applyRequestMetadata(method, attrs, executor, applier);
193+
callCredentials.applyRequestMetadata(new RequestInfoImpl(), executor, applier);
197194

198195
verify(credentials).getRequestMetadata(eq(expectedUri));
199196
verify(applier).fail(statusCaptor.capture());
@@ -209,7 +206,7 @@ public void credentialsFailsWithRuntimeException() throws Exception {
209206

210207
GoogleAuthLibraryCallCredentials callCredentials =
211208
new GoogleAuthLibraryCallCredentials(credentials);
212-
callCredentials.applyRequestMetadata(method, attrs, executor, applier);
209+
callCredentials.applyRequestMetadata(new RequestInfoImpl(), executor, applier);
213210

214211
verify(credentials).getRequestMetadata(eq(expectedUri));
215212
verify(applier).fail(statusCaptor.capture());
@@ -229,7 +226,7 @@ public void credentialsReturnNullMetadata() throws Exception {
229226
GoogleAuthLibraryCallCredentials callCredentials =
230227
new GoogleAuthLibraryCallCredentials(credentials);
231228
for (int i = 0; i < 3; i++) {
232-
callCredentials.applyRequestMetadata(method, attrs, executor, applier);
229+
callCredentials.applyRequestMetadata(new RequestInfoImpl(), executor, applier);
233230
}
234231

235232
verify(credentials, times(3)).getRequestMetadata(eq(expectedUri));
@@ -255,14 +252,11 @@ public AccessToken refreshAccessToken() throws IOException {
255252
return token;
256253
}
257254
};
258-
// Security level should not impact non-GoogleCredentials
259-
Attributes securityNone = attrs.toBuilder()
260-
.set(CallCredentials.ATTR_SECURITY_LEVEL, SecurityLevel.NONE)
261-
.build();
262255

263256
GoogleAuthLibraryCallCredentials callCredentials =
264257
new GoogleAuthLibraryCallCredentials(credentials);
265-
callCredentials.applyRequestMetadata(method, securityNone, executor, applier);
258+
callCredentials.applyRequestMetadata(
259+
new RequestInfoImpl(SecurityLevel.NONE), executor, applier);
266260
assertEquals(1, runPendingRunnables());
267261

268262
verify(applier).apply(headersCaptor.capture());
@@ -276,13 +270,11 @@ public AccessToken refreshAccessToken() throws IOException {
276270
public void googleCredential_privacyAndIntegrityAllowed() {
277271
final AccessToken token = new AccessToken("allyourbase", new Date(Long.MAX_VALUE));
278272
final Credentials credentials = GoogleCredentials.create(token);
279-
Attributes privacy = attrs.toBuilder()
280-
.set(CallCredentials.ATTR_SECURITY_LEVEL, SecurityLevel.PRIVACY_AND_INTEGRITY)
281-
.build();
282273

283274
GoogleAuthLibraryCallCredentials callCredentials =
284275
new GoogleAuthLibraryCallCredentials(credentials);
285-
callCredentials.applyRequestMetadata(method, privacy, executor, applier);
276+
callCredentials.applyRequestMetadata(
277+
new RequestInfoImpl(SecurityLevel.PRIVACY_AND_INTEGRITY), executor, applier);
286278
runPendingRunnables();
287279

288280
verify(applier).apply(headersCaptor.capture());
@@ -297,33 +289,11 @@ public void googleCredential_integrityDenied() {
297289
final AccessToken token = new AccessToken("allyourbase", new Date(Long.MAX_VALUE));
298290
final Credentials credentials = GoogleCredentials.create(token);
299291
// Anything less than PRIVACY_AND_INTEGRITY should fail
300-
Attributes integrity = attrs.toBuilder()
301-
.set(CallCredentials.ATTR_SECURITY_LEVEL, SecurityLevel.INTEGRITY)
302-
.build();
303-
304-
GoogleAuthLibraryCallCredentials callCredentials =
305-
new GoogleAuthLibraryCallCredentials(credentials);
306-
callCredentials.applyRequestMetadata(method, integrity, executor, applier);
307-
runPendingRunnables();
308-
309-
verify(applier).fail(statusCaptor.capture());
310-
Status status = statusCaptor.getValue();
311-
assertEquals(Status.Code.UNAUTHENTICATED, status.getCode());
312-
}
313-
314-
@Test
315-
public void googleCredential_nullSecurityDenied() {
316-
final AccessToken token = new AccessToken("allyourbase", new Date(Long.MAX_VALUE));
317-
final Credentials credentials = GoogleCredentials.create(token);
318-
// Null should not (for the moment) crash in horrible ways. In the future this could be changed,
319-
// since it technically isn't allowed per the API.
320-
Attributes integrity = attrs.toBuilder()
321-
.set(CallCredentials.ATTR_SECURITY_LEVEL, null)
322-
.build();
323292

324293
GoogleAuthLibraryCallCredentials callCredentials =
325294
new GoogleAuthLibraryCallCredentials(credentials);
326-
callCredentials.applyRequestMetadata(method, integrity, executor, applier);
295+
callCredentials.applyRequestMetadata(
296+
new RequestInfoImpl(SecurityLevel.INTEGRITY), executor, applier);
327297
runPendingRunnables();
328298

329299
verify(applier).fail(statusCaptor.capture());
@@ -335,20 +305,12 @@ public void googleCredential_nullSecurityDenied() {
335305
public void serviceUri() throws Exception {
336306
GoogleAuthLibraryCallCredentials callCredentials =
337307
new GoogleAuthLibraryCallCredentials(credentials);
338-
callCredentials.applyRequestMetadata(method,
339-
Attributes.newBuilder()
340-
.setAll(attrs)
341-
.set(CallCredentials.ATTR_AUTHORITY, "example.com:443")
342-
.build(),
343-
executor, applier);
308+
callCredentials.applyRequestMetadata(
309+
new RequestInfoImpl("example.com:443"), executor, applier);
344310
verify(credentials).getRequestMetadata(eq(new URI("https://example.com/a.service")));
345311

346-
callCredentials.applyRequestMetadata(method,
347-
Attributes.newBuilder()
348-
.setAll(attrs)
349-
.set(CallCredentials.ATTR_AUTHORITY, "example.com:123")
350-
.build(),
351-
executor, applier);
312+
callCredentials.applyRequestMetadata(
313+
new RequestInfoImpl("example.com:123"), executor, applier);
352314
verify(credentials).getRequestMetadata(eq(new URI("https://example.com:123/a.service")));
353315
}
354316

@@ -366,7 +328,7 @@ public AccessToken refreshAccessToken() {
366328

367329
GoogleAuthLibraryCallCredentials callCredentials =
368330
new GoogleAuthLibraryCallCredentials(credentials);
369-
callCredentials.applyRequestMetadata(method, attrs, executor, applier);
331+
callCredentials.applyRequestMetadata(new RequestInfoImpl(), executor, applier);
370332
assertEquals(0, runPendingRunnables());
371333

372334
verify(applier).apply(headersCaptor.capture());
@@ -393,7 +355,7 @@ public AccessToken refreshAccessToken() {
393355

394356
GoogleAuthLibraryCallCredentials callCredentials =
395357
new GoogleAuthLibraryCallCredentials(credentials);
396-
callCredentials.applyRequestMetadata(method, attrs, executor, applier);
358+
callCredentials.applyRequestMetadata(new RequestInfoImpl(), executor, applier);
397359
assertEquals(1, runPendingRunnables());
398360

399361
verify(applier).apply(headersCaptor.capture());
@@ -412,7 +374,7 @@ public void oauthClassesNotInClassPath() throws Exception {
412374
assertNull(GoogleAuthLibraryCallCredentials.createJwtHelperOrNull(null));
413375
GoogleAuthLibraryCallCredentials callCredentials =
414376
new GoogleAuthLibraryCallCredentials(credentials, null);
415-
callCredentials.applyRequestMetadata(method, attrs, executor, applier);
377+
callCredentials.applyRequestMetadata(new RequestInfoImpl(), executor, applier);
416378

417379
verify(credentials).getRequestMetadata(eq(expectedUri));
418380
verify(applier).apply(headersCaptor.capture());
@@ -430,4 +392,46 @@ private int runPendingRunnables() {
430392
}
431393
return savedPendingRunnables.size();
432394
}
395+
396+
private final class RequestInfoImpl extends CallCredentials2.RequestInfo {
397+
final String authority;
398+
final SecurityLevel securityLevel;
399+
400+
RequestInfoImpl() {
401+
this(AUTHORITY, SECURITY_LEVEL);
402+
}
403+
404+
RequestInfoImpl(SecurityLevel securityLevel) {
405+
this(AUTHORITY, securityLevel);
406+
}
407+
408+
RequestInfoImpl(String authority) {
409+
this(authority, SECURITY_LEVEL);
410+
}
411+
412+
RequestInfoImpl(String authority, SecurityLevel securityLevel) {
413+
this.authority = authority;
414+
this.securityLevel = securityLevel;
415+
}
416+
417+
@Override
418+
public MethodDescriptor<?, ?> getMethodDescriptor() {
419+
return method;
420+
}
421+
422+
@Override
423+
public SecurityLevel getSecurityLevel() {
424+
return securityLevel;
425+
}
426+
427+
@Override
428+
public String getAuthority() {
429+
return authority;
430+
}
431+
432+
@Override
433+
public Attributes getTransportAttrs() {
434+
return Attributes.EMPTY;
435+
}
436+
}
433437
}

core/src/main/java/io/grpc/CallCredentials.java

+39-4
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,15 @@ public interface CallCredentials {
4040
* The security level of the transport. It is guaranteed to be present in the {@code attrs} passed
4141
* to {@link #applyRequestMetadata}. It is by default {@link SecurityLevel#NONE} but can be
4242
* overridden by the transport.
43+
*
44+
* @deprecated transport implementations should use {@code
45+
* io.grpc.internal.GrpcAttributes.ATTR_SECURITY_LEVEL} instead.
4346
*/
4447
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1914")
4548
@Grpc.TransportAttr
49+
@Deprecated
4650
public static final Key<SecurityLevel> ATTR_SECURITY_LEVEL =
47-
Key.create("io.grpc.CallCredentials.securityLevel");
51+
Key.create("io.grpc.internal.GrpcAttributes.securityLevel");
4852

4953
/**
5054
* The authority string used to authenticate the server. Usually it's the server's host name. It
@@ -54,6 +58,7 @@ public interface CallCredentials {
5458
*/
5559
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1914")
5660
@Grpc.TransportAttr
61+
@Deprecated
5762
public static final Key<String> ATTR_AUTHORITY = Key.create("io.grpc.CallCredentials.authority");
5863

5964
/**
@@ -73,8 +78,11 @@ public interface CallCredentials {
7378
* needs to perform blocking operations.
7479
* @param applier The outlet of the produced headers. It can be called either before or after this
7580
* method returns.
81+
*
82+
* @deprecated implement {@link CallCredentials2} instead.
7683
*/
7784
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1914")
85+
@Deprecated
7886
void applyRequestMetadata(
7987
MethodDescriptor<?, ?> method, Attributes attrs,
8088
Executor appExecutor, MetadataApplier applier);
@@ -92,16 +100,43 @@ void applyRequestMetadata(
92100
* <p>Exactly one of its methods must be called to make the RPC proceed.
93101
*/
94102
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1914")
95-
public interface MetadataApplier {
103+
public abstract static class MetadataApplier {
96104
/**
97105
* Called when headers are successfully generated. They will be merged into the original
98106
* headers.
99107
*/
100-
void apply(Metadata headers);
108+
public abstract void apply(Metadata headers);
101109

102110
/**
103111
* Called when there has been an error when preparing the headers. This will fail the RPC.
104112
*/
105-
void fail(Status status);
113+
public abstract void fail(Status status);
114+
}
115+
116+
/**
117+
* The request-related information passed to {@code CallCredentials2.applyRequestMetadata()}.
118+
*/
119+
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1914")
120+
public abstract static class RequestInfo {
121+
/**
122+
* The method descriptor of this RPC.
123+
*/
124+
public abstract MethodDescriptor<?, ?> getMethodDescriptor();
125+
126+
/**
127+
* The security level on the transport.
128+
*/
129+
public abstract SecurityLevel getSecurityLevel();
130+
131+
/**
132+
* Returns the authority string used to authenticate the server for this call.
133+
*/
134+
public abstract String getAuthority();
135+
136+
/**
137+
* Returns the transport attributes.
138+
*/
139+
@Grpc.TransportAttr
140+
public abstract Attributes getTransportAttrs();
106141
}
107142
}

0 commit comments

Comments
 (0)