1 /* 2 * Copyright 2023 The gRPC Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package io.grpc.binder; 18 19 import static com.google.common.base.Preconditions.checkNotNull; 20 21 import android.content.pm.PackageManager; 22 import android.os.Build.VERSION_CODES; 23 import android.os.UserHandle; 24 import androidx.annotation.RequiresApi; 25 import io.grpc.Context; 26 import io.grpc.Contexts; 27 import io.grpc.ExperimentalApi; 28 import io.grpc.Metadata; 29 import io.grpc.ServerCall; 30 import io.grpc.ServerCallHandler; 31 import io.grpc.ServerInterceptor; 32 import io.grpc.binder.internal.BinderTransport; 33 import javax.annotation.Nullable; 34 35 /** Static methods that operate on {@link PeerUid}. */ 36 @ExperimentalApi("https://github.com/grpc/grpc-java/issues/8022") 37 public final class PeerUids { 38 /** 39 * The client's authentic identity will be stored under this key in the server {@link Context}. 40 * 41 * <p>In order for this key to be populated, the interceptor returned by {@link 42 * #newPeerIdentifyingServerInterceptor} must be attached to the service. Note that the Context 43 * must be propagated correctly across threads for this key to be populated when read from other 44 * threads. 45 */ 46 public static final Context.Key<PeerUid> REMOTE_PEER = Context.key("remote-peer"); 47 48 /** 49 * Returns package names associated with the given peer's uid according to {@link 50 * PackageManager#getPackagesForUid(int)}. 51 * 52 * <p><em>WARNING</em>: Apps installed from untrusted sources can set any package name they want. 53 * Don't depend on package names for security -- use {@link SecurityPolicies} instead. 54 */ getInsecurePackagesForUid(PackageManager packageManager, PeerUid who)55 public static String[] getInsecurePackagesForUid(PackageManager packageManager, PeerUid who) { 56 return packageManager.getPackagesForUid(who.getUid()); 57 } 58 59 /** 60 * Retrieves the "official name" associated with this uid, as specified by {@link 61 * PackageManager#getNameForUid(int)}. 62 */ 63 @Nullable getNameForUid(PackageManager packageManager, PeerUid who)64 public static String getNameForUid(PackageManager packageManager, PeerUid who) { 65 return packageManager.getNameForUid(who.getUid()); 66 } 67 68 /** 69 * Retrieves the {@link UserHandle} associated with this uid according to {@link 70 * UserHandle#getUserHandleForUid}. 71 */ 72 @RequiresApi(api = VERSION_CODES.N) getUserHandleForUid(PeerUid who)73 public static UserHandle getUserHandleForUid(PeerUid who) { 74 return UserHandle.getUserHandleForUid(who.getUid()); 75 } 76 77 /** 78 * Creates an interceptor that exposes the client's identity in the {@link Context} under {@link 79 * #REMOTE_PEER}. 80 * 81 * <p>The returned interceptor only works with the Android Binder transport. If installed 82 * elsewhere, all intercepted requests will fail without ever reaching application-layer 83 * processing. 84 */ newPeerIdentifyingServerInterceptor()85 public static ServerInterceptor newPeerIdentifyingServerInterceptor() { 86 return new ServerInterceptor() { 87 @Override 88 public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall( 89 ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) { 90 Context context = Context.current(); 91 PeerUid client = 92 new PeerUid( 93 checkNotNull( 94 call.getAttributes().get(BinderTransport.REMOTE_UID), 95 "Expected BinderTransport attribute REMOTE_UID was missing. Is this " 96 + "interceptor installed on an unsupported type of Server?")); 97 return Contexts.interceptCall(context.withValue(REMOTE_PEER, client), call, headers, next); 98 } 99 }; 100 } 101 102 private PeerUids() {} 103 }