Skip to content

Commit ddf171b

Browse files
committed
binder: describe security policy evaluation failures uniformly as 'Authorization future failed'
1 parent bc01994 commit ddf171b

4 files changed

Lines changed: 63 additions & 11 deletions

File tree

binder/src/main/java/io/grpc/binder/ServerSecurityPolicy.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,10 @@ public Status checkAuthorizationForService(int uid, String serviceName) {
7272
@CheckReturnValue
7373
ListenableFuture<Status> checkAuthorizationForServiceAsync(int uid, String serviceName) {
7474
SecurityPolicy securityPolicy = perServicePolicies.getOrDefault(serviceName, defaultPolicy);
75-
if (securityPolicy instanceof AsyncSecurityPolicy) {
76-
return ((AsyncSecurityPolicy) securityPolicy).checkAuthorizationAsync(uid);
77-
}
78-
7975
try {
76+
if (securityPolicy instanceof AsyncSecurityPolicy) {
77+
return ((AsyncSecurityPolicy) securityPolicy).checkAuthorizationAsync(uid);
78+
}
8079
Status status = securityPolicy.checkAuthorization(uid);
8180
return Futures.immediateFuture(status);
8281
} catch (Exception e) {

binder/src/main/java/io/grpc/binder/internal/BinderTransportSecurity.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,7 @@ public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
110110
authStatus = Futures.getDone(authStatusFuture);
111111
} catch (ExecutionException | CancellationException e) {
112112
// Failed futures are treated as an internal error rather than a security rejection.
113-
authStatus = Status.INTERNAL.withCause(e);
114-
@Nullable String message = e.getMessage();
115-
if (message != null) {
116-
authStatus = authStatus.withDescription(message);
117-
}
113+
authStatus = Status.INTERNAL.withCause(e).withDescription("Authorization future failed");
118114
}
119115

120116
if (authStatus.isOk()) {

binder/src/test/java/io/grpc/binder/RobolectricBinderSecurityTest.java

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,10 +161,29 @@ public void testAsyncServerSecurityPolicy_failed_returnsFailureStatus() throws E
161161

162162
@Test
163163
public void testAsyncServerSecurityPolicy_failedFuture_failsWithCodeInternal() throws Exception {
164-
ListenableFuture<Status> status = makeCall();
164+
ListenableFuture<Status> status1 = makeCall();
165165
statusesToSet.take().setException(new IllegalStateException("oops"));
166166

167-
assertThat(status.get().getCode()).isEqualTo(Status.Code.INTERNAL);
167+
Status result1 = status1.get();
168+
assertThat(result1.getCode()).isEqualTo(Status.Code.INTERNAL);
169+
assertThat(result1.getDescription()).isEqualTo("Authorization future failed");
170+
171+
// Subsequent call on the same channel should also get uniform opaque failure description
172+
ListenableFuture<Status> status2 = makeCall();
173+
Status result2 = status2.get();
174+
assertThat(result2.getCode()).isEqualTo(Status.Code.INTERNAL);
175+
assertThat(result2.getDescription()).isEqualTo("Authorization future failed");
176+
}
177+
178+
@Test
179+
public void testAsyncServerSecurityPolicy_cancelledFuture_failsWithUniformOpaqueDescription()
180+
throws Exception {
181+
ListenableFuture<Status> status1 = makeCall();
182+
statusesToSet.take().cancel(true);
183+
184+
Status result1 = status1.get();
185+
assertThat(result1.getCode()).isEqualTo(Status.Code.INTERNAL);
186+
assertThat(result1.getDescription()).isEqualTo("Authorization future failed");
168187
}
169188

170189
@Test

binder/src/test/java/io/grpc/binder/ServerSecurityPolicyTest.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,44 @@ public void testPerServiceNoDefaultAsync() throws Exception {
333333
.isEqualTo(Status.PERMISSION_DENIED.getCode());
334334
}
335335

336+
@Test
337+
public void testAsyncSecurityPolicy_throwsExceptionSynchronously_returnsFailedFuture() {
338+
policy =
339+
ServerSecurityPolicy.newBuilder()
340+
.servicePolicy(
341+
SERVICE1,
342+
asyncPolicy(
343+
uid -> {
344+
throw new IllegalStateException("Sync policy error");
345+
}))
346+
.build();
347+
348+
ListenableFuture<Status> future = policy.checkAuthorizationForServiceAsync(MY_UID, SERVICE1);
349+
assertThat(future.isDone()).isTrue();
350+
ExecutionException thrown = assertThrows(ExecutionException.class, future::get);
351+
assertThat(thrown.getCause()).isInstanceOf(IllegalStateException.class);
352+
assertThat(thrown.getCause().getMessage()).isEqualTo("Sync policy error");
353+
}
354+
355+
@Test
356+
public void testSecurityPolicy_throwsExceptionSynchronously_returnsFailedFuture() {
357+
policy =
358+
ServerSecurityPolicy.newBuilder()
359+
.servicePolicy(
360+
SERVICE1,
361+
policy(
362+
uid -> {
363+
throw new IllegalArgumentException("Sync standard policy error");
364+
}))
365+
.build();
366+
367+
ListenableFuture<Status> future = policy.checkAuthorizationForServiceAsync(MY_UID, SERVICE1);
368+
assertThat(future.isDone()).isTrue();
369+
ExecutionException thrown = assertThrows(ExecutionException.class, future::get);
370+
assertThat(thrown.getCause()).isInstanceOf(IllegalArgumentException.class);
371+
assertThat(thrown.getCause().getMessage()).isEqualTo("Sync standard policy error");
372+
}
373+
336374
/**
337375
* Shortcut for invoking {@link ServerSecurityPolicy#checkAuthorizationForServiceAsync} without
338376
* dealing with concurrency details. Returns a {link @Status.Code} for convenience.

0 commit comments

Comments
 (0)