mirror of https://github.com/grpc/grpc-java.git
Merge 0d4243de8b
into 42e1829b37
This commit is contained in:
commit
8677177cf7
|
@ -16,6 +16,9 @@
|
||||||
|
|
||||||
package io.grpc.binder;
|
package io.grpc.binder;
|
||||||
|
|
||||||
|
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||||
|
import static com.google.common.util.concurrent.Futures.immediateFuture;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.admin.DevicePolicyManager;
|
import android.app.admin.DevicePolicyManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
@ -32,6 +35,9 @@ import com.google.common.base.Predicate;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.hash.Hashing;
|
import com.google.common.hash.Hashing;
|
||||||
|
import com.google.common.util.concurrent.Futures;
|
||||||
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
import com.google.common.util.concurrent.MoreExecutors;
|
||||||
import com.google.errorprone.annotations.CheckReturnValue;
|
import com.google.errorprone.annotations.CheckReturnValue;
|
||||||
import io.grpc.ExperimentalApi;
|
import io.grpc.ExperimentalApi;
|
||||||
import io.grpc.Status;
|
import io.grpc.Status;
|
||||||
|
@ -333,6 +339,9 @@ public final class SecurityPolicies {
|
||||||
* Creates a {@link SecurityPolicy} that allows access if and only if *all* of the specified
|
* Creates a {@link SecurityPolicy} that allows access if and only if *all* of the specified
|
||||||
* {@code securityPolicies} allow access.
|
* {@code securityPolicies} allow access.
|
||||||
*
|
*
|
||||||
|
* <p>If any of the policies is an {@link AsyncSecurityPolicy}, then all policies may be evaluated
|
||||||
|
* concurrently to speed up the success scenario.
|
||||||
|
*
|
||||||
* @param securityPolicies the security policies that all must allow access.
|
* @param securityPolicies the security policies that all must allow access.
|
||||||
* @throws NullPointerException if any of the inputs are {@code null}.
|
* @throws NullPointerException if any of the inputs are {@code null}.
|
||||||
* @throws IllegalArgumentException if {@code securityPolicies} is empty.
|
* @throws IllegalArgumentException if {@code securityPolicies} is empty.
|
||||||
|
@ -341,10 +350,17 @@ public final class SecurityPolicies {
|
||||||
Preconditions.checkNotNull(securityPolicies, "securityPolicies");
|
Preconditions.checkNotNull(securityPolicies, "securityPolicies");
|
||||||
Preconditions.checkArgument(securityPolicies.length > 0, "securityPolicies must not be empty");
|
Preconditions.checkArgument(securityPolicies.length > 0, "securityPolicies must not be empty");
|
||||||
|
|
||||||
return allOfSecurityPolicy(securityPolicies);
|
boolean anyAsync =
|
||||||
|
Arrays
|
||||||
|
.stream(securityPolicies)
|
||||||
|
.anyMatch(policy -> policy instanceof AsyncSecurityPolicy);
|
||||||
|
|
||||||
|
return anyAsync
|
||||||
|
? allOfSecurityPolicyAsync(securityPolicies)
|
||||||
|
: allOfSecurityPolicySync(securityPolicies);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SecurityPolicy allOfSecurityPolicy(SecurityPolicy... securityPolicies) {
|
private static SecurityPolicy allOfSecurityPolicySync(SecurityPolicy... securityPolicies) {
|
||||||
return new SecurityPolicy() {
|
return new SecurityPolicy() {
|
||||||
@Override
|
@Override
|
||||||
public Status checkAuthorization(int uid) {
|
public Status checkAuthorization(int uid) {
|
||||||
|
@ -360,6 +376,33 @@ public final class SecurityPolicies {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static SecurityPolicy allOfSecurityPolicyAsync(SecurityPolicy... securityPolicies) {
|
||||||
|
return new AsyncSecurityPolicy() {
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<Status> checkAuthorizationAsync(int uid) {
|
||||||
|
ImmutableList<ListenableFuture<Status>> allStatuses =
|
||||||
|
Arrays.stream(securityPolicies).map(policy -> {
|
||||||
|
AsyncSecurityPolicy asyncPolicy =
|
||||||
|
policy instanceof AsyncSecurityPolicy ? (AsyncSecurityPolicy) policy :
|
||||||
|
new AsyncSecurityPolicy() {
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<Status> checkAuthorizationAsync(int uid) {
|
||||||
|
return immediateFuture(policy.checkAuthorization(uid));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return asyncPolicy.checkAuthorizationAsync(uid);
|
||||||
|
}).collect(toImmutableList());
|
||||||
|
ListenableFuture<List<Status>> futureStatuses = Futures.allAsList(allStatuses);
|
||||||
|
|
||||||
|
return Futures
|
||||||
|
.transform(
|
||||||
|
futureStatuses,statuses ->
|
||||||
|
statuses.stream().filter(status -> !status.isOk()).findFirst().orElse(Status.OK),
|
||||||
|
MoreExecutors.directExecutor());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@link SecurityPolicy} that allows access if *any* of the specified {@code
|
* Creates a {@link SecurityPolicy} that allows access if *any* of the specified {@code
|
||||||
* securityPolicies} allow access.
|
* securityPolicies} allow access.
|
||||||
|
|
|
@ -22,6 +22,7 @@ import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
|
||||||
import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
|
import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
|
||||||
import static com.google.common.base.Preconditions.checkState;
|
import static com.google.common.base.Preconditions.checkState;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
import static com.google.common.util.concurrent.Futures.immediateFuture;
|
||||||
import static org.robolectric.Shadows.shadowOf;
|
import static org.robolectric.Shadows.shadowOf;
|
||||||
|
|
||||||
import android.app.admin.DevicePolicyManager;
|
import android.app.admin.DevicePolicyManager;
|
||||||
|
@ -35,9 +36,11 @@ import androidx.test.core.app.ApplicationProvider;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.hash.Hashing;
|
import com.google.common.hash.Hashing;
|
||||||
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import io.grpc.Status;
|
import io.grpc.Status;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.function.Function;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
@ -534,6 +537,29 @@ public final class SecurityPoliciesTest {
|
||||||
.contains("Not allowed SecurityPolicy");
|
.contains("Not allowed SecurityPolicy");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAllOfAsync_succeedsIfAllSecurityPoliciesAllowed() {
|
||||||
|
policy =
|
||||||
|
SecurityPolicies.allOf(
|
||||||
|
SecurityPolicies.internalOnly(),
|
||||||
|
makeAsyncPolicy(uid -> immediateFuture(Status.OK)));
|
||||||
|
|
||||||
|
assertThat(policy.checkAuthorization(MY_UID).getCode()).isEqualTo(Status.OK.getCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAllOfAsync_failsIfOneSecurityPoliciesNotAllowed() {
|
||||||
|
policy =
|
||||||
|
SecurityPolicies.allOf(
|
||||||
|
SecurityPolicies.internalOnly(),
|
||||||
|
makeAsyncPolicy(uid -> immediateFuture(Status.OK)),
|
||||||
|
makeAsyncPolicy(uid -> immediateFuture(Status.ABORTED)),
|
||||||
|
makeAsyncPolicy(uid -> immediateFuture(Status.INVALID_ARGUMENT)));
|
||||||
|
|
||||||
|
assertThat(policy.checkAuthorization(MY_UID).getCode())
|
||||||
|
.isEqualTo(Status.Code.ABORTED);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAnyOf_succeedsIfAnySecurityPoliciesAllowed() throws Exception {
|
public void testAnyOf_succeedsIfAnySecurityPoliciesAllowed() throws Exception {
|
||||||
RecordingPolicy recordingPolicy = new RecordingPolicy();
|
RecordingPolicy recordingPolicy = new RecordingPolicy();
|
||||||
|
@ -703,4 +729,13 @@ public final class SecurityPoliciesTest {
|
||||||
private static byte[] getSha256Hash(Signature signature) {
|
private static byte[] getSha256Hash(Signature signature) {
|
||||||
return Hashing.sha256().hashBytes(signature.toByteArray()).asBytes();
|
return Hashing.sha256().hashBytes(signature.toByteArray()).asBytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static AsyncSecurityPolicy makeAsyncPolicy(Function<Integer, ListenableFuture<Status>> statusProvider) {
|
||||||
|
return new AsyncSecurityPolicy() {
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<Status> checkAuthorizationAsync(int uid) {
|
||||||
|
return statusProvider.apply(uid);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue