• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }