• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 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 android.Manifest.permission.ACCESS_COARSE_LOCATION;
20 import static android.Manifest.permission.ACCESS_FINE_LOCATION;
21 import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
22 import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
23 import static com.google.common.base.Preconditions.checkState;
24 import static com.google.common.truth.Truth.assertThat;
25 import static org.robolectric.Shadows.shadowOf;
26 
27 import android.app.admin.DevicePolicyManager;
28 import android.content.ComponentName;
29 import android.content.Context;
30 import android.content.pm.PackageInfo;
31 import android.content.pm.PackageManager;
32 import android.content.pm.Signature;
33 import android.os.Build;
34 import android.os.Build.VERSION;
35 import android.os.Build.VERSION_CODES;
36 import android.os.Process;
37 import androidx.test.core.app.ApplicationProvider;
38 import com.google.common.collect.ImmutableList;
39 import com.google.common.collect.ImmutableSet;
40 import com.google.common.hash.Hashing;
41 import io.grpc.Status;
42 import java.util.HashMap;
43 import java.util.concurrent.atomic.AtomicInteger;
44 import org.junit.Before;
45 import org.junit.Test;
46 import org.junit.runner.RunWith;
47 import org.robolectric.RobolectricTestRunner;
48 import org.robolectric.annotation.Config;
49 
50 @RunWith(RobolectricTestRunner.class)
51 public final class SecurityPoliciesTest {
52 
53   private static final int MY_UID = Process.myUid();
54   private static final int OTHER_UID = MY_UID + 1;
55   private static final int OTHER_UID_SAME_SIGNATURE = MY_UID + 2;
56   private static final int OTHER_UID_UNKNOWN = MY_UID + 4;
57 
58   private static final String PERMISSION_DENIED_REASONS = "some reasons";
59 
60   private static final Signature SIG1 = new Signature("1234");
61   private static final Signature SIG2 = new Signature("4321");
62 
63   private static final String OTHER_UID_PACKAGE_NAME = "other.package";
64   private static final String OTHER_UID_SAME_SIGNATURE_PACKAGE_NAME = "other.package.samesignature";
65 
66   private Context appContext;
67   private PackageManager packageManager;
68   private DevicePolicyManager devicePolicyManager;
69 
70   private SecurityPolicy policy;
71 
72   @Before
setUp()73   public void setUp() {
74     appContext = ApplicationProvider.getApplicationContext();
75     packageManager = appContext.getPackageManager();
76     devicePolicyManager =
77         (DevicePolicyManager) appContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
78   }
79 
80   @SuppressWarnings("deprecation")
installPackages(int uid, PackageInfo... packageInfo)81   private void installPackages(int uid, PackageInfo... packageInfo) {
82     String[] packageNames = new String[packageInfo.length];
83     for (int i = 0; i < packageInfo.length; i++) {
84       shadowOf(packageManager).installPackage(packageInfo[i]);
85       packageNames[i] = packageInfo[i].packageName;
86     }
87     shadowOf(packageManager).setPackagesForUid(uid, packageNames);
88   }
89 
90   @Test
testInternalOnly()91   public void testInternalOnly() throws Exception {
92     policy = SecurityPolicies.internalOnly();
93 
94     assertThat(policy.checkAuthorization(MY_UID).getCode()).isEqualTo(Status.OK.getCode());
95     assertThat(policy.checkAuthorization(OTHER_UID).getCode())
96         .isEqualTo(Status.PERMISSION_DENIED.getCode());
97   }
98 
99   @Test
testPermissionDenied()100   public void testPermissionDenied() throws Exception {
101     policy = SecurityPolicies.permissionDenied(PERMISSION_DENIED_REASONS);
102     assertThat(policy.checkAuthorization(MY_UID).getCode())
103         .isEqualTo(Status.PERMISSION_DENIED.getCode());
104     assertThat(policy.checkAuthorization(MY_UID).getDescription())
105         .isEqualTo(PERMISSION_DENIED_REASONS);
106     assertThat(policy.checkAuthorization(OTHER_UID).getCode())
107         .isEqualTo(Status.PERMISSION_DENIED.getCode());
108     assertThat(policy.checkAuthorization(OTHER_UID).getDescription())
109         .isEqualTo(PERMISSION_DENIED_REASONS);
110   }
111 
112   @Test
testHasSignature_succeedsIfPackageNameAndSignaturesMatch()113   public void testHasSignature_succeedsIfPackageNameAndSignaturesMatch()
114       throws Exception {
115     PackageInfo info =
116         newBuilder().setPackageName(OTHER_UID_PACKAGE_NAME).setSignatures(SIG2).build();
117 
118     installPackages(OTHER_UID, info);
119 
120     policy = SecurityPolicies.hasSignature(packageManager, OTHER_UID_PACKAGE_NAME, SIG2);
121 
122     // THEN UID for package that has SIG2 will be authorized
123     assertThat(policy.checkAuthorization(OTHER_UID).getCode()).isEqualTo(Status.OK.getCode());
124   }
125 
126   @Test
testHasSignature_failsIfPackageNameDoesNotMatch()127   public void testHasSignature_failsIfPackageNameDoesNotMatch() throws Exception {
128     PackageInfo info =
129         newBuilder()
130             .setPackageName(OTHER_UID_SAME_SIGNATURE_PACKAGE_NAME)
131             .setSignatures(SIG1)
132             .build();
133 
134     installPackages(OTHER_UID_SAME_SIGNATURE, info);
135 
136     policy = SecurityPolicies.hasSignature(packageManager, appContext.getPackageName(), SIG1);
137 
138     // THEN UID for package that has SIG1 but different package name will not be authorized
139     assertThat(policy.checkAuthorization(OTHER_UID_SAME_SIGNATURE).getCode())
140         .isEqualTo(Status.PERMISSION_DENIED.getCode());
141   }
142 
143   @Test
testHasSignature_failsIfSignatureDoesNotMatch()144   public void testHasSignature_failsIfSignatureDoesNotMatch() throws Exception {
145     PackageInfo info =
146         newBuilder().setPackageName(OTHER_UID_PACKAGE_NAME).setSignatures(SIG2).build();
147 
148     installPackages(OTHER_UID, info);
149 
150     policy = SecurityPolicies.hasSignature(packageManager, OTHER_UID_PACKAGE_NAME, SIG1);
151 
152     // THEN UID for package that doesn't have SIG1 will not be authorized
153     assertThat(policy.checkAuthorization(OTHER_UID).getCode())
154         .isEqualTo(Status.PERMISSION_DENIED.getCode());
155   }
156 
157   @Test
testOneOfSignatures_succeedsIfPackageNameAndSignaturesMatch()158   public void testOneOfSignatures_succeedsIfPackageNameAndSignaturesMatch()
159       throws Exception {
160     PackageInfo info =
161         newBuilder().setPackageName(OTHER_UID_PACKAGE_NAME).setSignatures(SIG2).build();
162 
163     installPackages(OTHER_UID, info);
164 
165     policy =
166         SecurityPolicies.oneOfSignatures(
167             packageManager, OTHER_UID_PACKAGE_NAME, ImmutableList.of(SIG2));
168 
169     // THEN UID for package that has SIG2 will be authorized
170     assertThat(policy.checkAuthorization(OTHER_UID).getCode()).isEqualTo(Status.OK.getCode());
171   }
172 
173   @Test
testOneOfSignature_failsIfAllSignaturesDoNotMatch()174   public void testOneOfSignature_failsIfAllSignaturesDoNotMatch() throws Exception {
175     PackageInfo info =
176         newBuilder()
177             .setPackageName(OTHER_UID_SAME_SIGNATURE_PACKAGE_NAME)
178             .setSignatures(SIG1)
179             .build();
180 
181     installPackages(OTHER_UID_SAME_SIGNATURE, info);
182 
183     policy =
184         SecurityPolicies.oneOfSignatures(
185             packageManager,
186             appContext.getPackageName(),
187             ImmutableList.of(SIG1, new Signature("1314")));
188 
189     // THEN UID for package that has SIG1 but different package name will not be authorized
190     assertThat(policy.checkAuthorization(OTHER_UID_SAME_SIGNATURE).getCode())
191         .isEqualTo(Status.PERMISSION_DENIED.getCode());
192   }
193 
194   @Test
testOneOfSignature_succeedsIfPackageNameAndOneOfSignaturesMatch()195   public void testOneOfSignature_succeedsIfPackageNameAndOneOfSignaturesMatch()
196       throws Exception {
197     PackageInfo info =
198         newBuilder().setPackageName(OTHER_UID_PACKAGE_NAME).setSignatures(SIG2).build();
199 
200     installPackages(OTHER_UID, info);
201 
202     policy =
203         SecurityPolicies.oneOfSignatures(
204             packageManager, OTHER_UID_PACKAGE_NAME, ImmutableList.of(SIG1, SIG2));
205 
206     // THEN UID for package that has SIG2 will be authorized
207     assertThat(policy.checkAuthorization(OTHER_UID).getCode()).isEqualTo(Status.OK.getCode());
208   }
209 
210   @Test
testHasSignature_failsIfUidUnknown()211   public void testHasSignature_failsIfUidUnknown() throws Exception {
212     policy =
213         SecurityPolicies.hasSignature(
214             packageManager,
215             appContext.getPackageName(),
216             SIG1);
217 
218     assertThat(policy.checkAuthorization(OTHER_UID_UNKNOWN).getCode())
219         .isEqualTo(Status.UNAUTHENTICATED.getCode());
220   }
221 
222   @Test
testHasPermissions_sharedUserId_succeedsIfAllPackageHavePermissions()223   public void testHasPermissions_sharedUserId_succeedsIfAllPackageHavePermissions()
224       throws Exception {
225     PackageInfo info =
226         newBuilder()
227             .setPackageName(OTHER_UID_PACKAGE_NAME)
228             .setPermission(ACCESS_FINE_LOCATION, REQUESTED_PERMISSION_GRANTED)
229             .setPermission(ACCESS_COARSE_LOCATION, REQUESTED_PERMISSION_GRANTED)
230             .build();
231 
232     PackageInfo infoSamePerms =
233         newBuilder()
234             .setPackageName(OTHER_UID_SAME_SIGNATURE_PACKAGE_NAME)
235             .setPermission(ACCESS_FINE_LOCATION, REQUESTED_PERMISSION_GRANTED)
236             .setPermission(ACCESS_COARSE_LOCATION, REQUESTED_PERMISSION_GRANTED)
237             .build();
238 
239     installPackages(OTHER_UID, info, infoSamePerms);
240 
241     policy =
242         SecurityPolicies.hasPermissions(
243             packageManager, ImmutableSet.of(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION));
244     assertThat(policy.checkAuthorization(OTHER_UID).getCode()).isEqualTo(Status.OK.getCode());
245   }
246 
247   @Test
testHasPermissions_sharedUserId_failsIfOnePackageHasNoPermissions()248   public void testHasPermissions_sharedUserId_failsIfOnePackageHasNoPermissions() throws Exception {
249     PackageInfo info =
250         newBuilder()
251             .setPackageName(OTHER_UID_PACKAGE_NAME)
252             .setPermission(ACCESS_FINE_LOCATION, REQUESTED_PERMISSION_GRANTED)
253             .build();
254 
255     PackageInfo infoNoPerms =
256         newBuilder()
257             .setPackageName(OTHER_UID_SAME_SIGNATURE_PACKAGE_NAME)
258             .setPermission(ACCESS_FINE_LOCATION, 0)
259             .build();
260 
261     installPackages(OTHER_UID, info, infoNoPerms);
262 
263     policy = SecurityPolicies.hasPermissions(packageManager, ImmutableSet.of(ACCESS_FINE_LOCATION));
264     assertThat(policy.checkAuthorization(OTHER_UID).getCode())
265         .isEqualTo(Status.PERMISSION_DENIED.getCode());
266     assertThat(policy.checkAuthorization(OTHER_UID).getDescription())
267         .contains(ACCESS_FINE_LOCATION);
268     assertThat(policy.checkAuthorization(OTHER_UID).getDescription())
269         .contains(OTHER_UID_SAME_SIGNATURE_PACKAGE_NAME);
270   }
271 
272   @Test
testHasPermissions_succeedsIfPackageHasPermissions()273   public void testHasPermissions_succeedsIfPackageHasPermissions() throws Exception {
274     PackageInfo info =
275         newBuilder()
276             .setPackageName(OTHER_UID_PACKAGE_NAME)
277             .setPermission(ACCESS_FINE_LOCATION, REQUESTED_PERMISSION_GRANTED)
278             .setPermission(ACCESS_COARSE_LOCATION, REQUESTED_PERMISSION_GRANTED)
279             .setPermission(WRITE_EXTERNAL_STORAGE, 0)
280             .build();
281 
282     installPackages(OTHER_UID, info);
283 
284     policy =
285         SecurityPolicies.hasPermissions(
286             packageManager, ImmutableSet.of(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION));
287     assertThat(policy.checkAuthorization(OTHER_UID).getCode()).isEqualTo(Status.OK.getCode());
288   }
289 
290   @Test
testHasPermissions_failsIfPackageDoesNotHaveOnePermission()291   public void testHasPermissions_failsIfPackageDoesNotHaveOnePermission() throws Exception {
292     PackageInfo info =
293         newBuilder()
294             .setPackageName(OTHER_UID_PACKAGE_NAME)
295             .setPermission(ACCESS_FINE_LOCATION, REQUESTED_PERMISSION_GRANTED)
296             .setPermission(ACCESS_COARSE_LOCATION, REQUESTED_PERMISSION_GRANTED)
297             .setPermission(WRITE_EXTERNAL_STORAGE, 0)
298             .build();
299 
300     installPackages(OTHER_UID, info);
301 
302     policy =
303         SecurityPolicies.hasPermissions(
304             packageManager, ImmutableSet.of(ACCESS_FINE_LOCATION, WRITE_EXTERNAL_STORAGE));
305     assertThat(policy.checkAuthorization(OTHER_UID).getCode())
306         .isEqualTo(Status.PERMISSION_DENIED.getCode());
307     assertThat(policy.checkAuthorization(OTHER_UID).getDescription())
308         .contains(WRITE_EXTERNAL_STORAGE);
309     assertThat(policy.checkAuthorization(OTHER_UID).getDescription())
310         .contains(OTHER_UID_PACKAGE_NAME);
311   }
312 
313   @Test
testHasPermissions_failsIfPackageDoesNotHavePermissions()314   public void testHasPermissions_failsIfPackageDoesNotHavePermissions() throws Exception {
315     PackageInfo info =
316         newBuilder()
317             .setPackageName(OTHER_UID_PACKAGE_NAME)
318             .setPermission(ACCESS_FINE_LOCATION, REQUESTED_PERMISSION_GRANTED)
319             .setPermission(ACCESS_COARSE_LOCATION, REQUESTED_PERMISSION_GRANTED)
320             .setPermission(WRITE_EXTERNAL_STORAGE, 0)
321             .build();
322 
323     installPackages(OTHER_UID, info);
324 
325     policy =
326         SecurityPolicies.hasPermissions(packageManager, ImmutableSet.of(WRITE_EXTERNAL_STORAGE));
327     assertThat(policy.checkAuthorization(OTHER_UID).getCode())
328         .isEqualTo(Status.PERMISSION_DENIED.getCode());
329     assertThat(policy.checkAuthorization(OTHER_UID).getDescription())
330         .contains(WRITE_EXTERNAL_STORAGE);
331     assertThat(policy.checkAuthorization(OTHER_UID).getDescription())
332         .contains(OTHER_UID_PACKAGE_NAME);
333   }
334 
335   @Test
336   @Config(sdk = 18)
testIsDeviceOwner_succeedsForDeviceOwner()337   public void testIsDeviceOwner_succeedsForDeviceOwner() throws Exception {
338     PackageInfo info =
339         newBuilder().setPackageName(OTHER_UID_PACKAGE_NAME).setSignatures(SIG2).build();
340 
341     installPackages(OTHER_UID, info);
342     shadowOf(devicePolicyManager)
343         .setDeviceOwner(new ComponentName(OTHER_UID_PACKAGE_NAME, "foo"));
344 
345     policy = SecurityPolicies.isDeviceOwner(appContext);
346 
347     assertThat(policy.checkAuthorization(OTHER_UID).getCode()).isEqualTo(Status.OK.getCode());
348   }
349 
350   @Test
351   @Config(sdk = 18)
testIsDeviceOwner_failsForNotDeviceOwner()352   public void testIsDeviceOwner_failsForNotDeviceOwner() throws Exception {
353     PackageInfo info =
354         newBuilder().setPackageName(OTHER_UID_PACKAGE_NAME).setSignatures(SIG2).build();
355 
356     installPackages(OTHER_UID, info);
357 
358     policy = SecurityPolicies.isDeviceOwner(appContext);
359 
360     assertThat(policy.checkAuthorization(OTHER_UID).getCode()).isEqualTo(Status.PERMISSION_DENIED.getCode());
361   }
362 
363   @Test
364   @Config(sdk = 18)
testIsDeviceOwner_failsWhenNoPackagesForUid()365   public void testIsDeviceOwner_failsWhenNoPackagesForUid() throws Exception {
366     policy = SecurityPolicies.isDeviceOwner(appContext);
367 
368     assertThat(policy.checkAuthorization(OTHER_UID).getCode()).isEqualTo(Status.UNAUTHENTICATED.getCode());
369   }
370 
371   @Test
372   @Config(sdk = 17)
testIsDeviceOwner_failsForSdkLevelTooLow()373   public void testIsDeviceOwner_failsForSdkLevelTooLow() throws Exception {
374     PackageInfo info =
375         newBuilder().setPackageName(OTHER_UID_PACKAGE_NAME).setSignatures(SIG2).build();
376 
377     installPackages(OTHER_UID, info);
378 
379     policy = SecurityPolicies.isDeviceOwner(appContext);
380 
381     assertThat(policy.checkAuthorization(OTHER_UID).getCode()).isEqualTo(Status.PERMISSION_DENIED.getCode());
382   }
383 
384   @Test
385   @Config(sdk = 21)
testIsProfileOwner_succeedsForProfileOwner()386   public void testIsProfileOwner_succeedsForProfileOwner() throws Exception {
387     PackageInfo info =
388         newBuilder().setPackageName(OTHER_UID_PACKAGE_NAME).setSignatures(SIG2).build();
389 
390     installPackages(OTHER_UID, info);
391     shadowOf(devicePolicyManager)
392         .setProfileOwner(new ComponentName(OTHER_UID_PACKAGE_NAME, "foo"));
393 
394     policy = SecurityPolicies.isProfileOwner(appContext);
395 
396     assertThat(policy.checkAuthorization(OTHER_UID).getCode()).isEqualTo(Status.OK.getCode());
397   }
398 
399   @Test
400   @Config(sdk = 21)
testIsProfileOwner_failsForNotProfileOwner()401   public void testIsProfileOwner_failsForNotProfileOwner() throws Exception {
402     PackageInfo info =
403         newBuilder().setPackageName(OTHER_UID_PACKAGE_NAME).setSignatures(SIG2).build();
404 
405     installPackages(OTHER_UID, info);
406 
407     policy = SecurityPolicies.isProfileOwner(appContext);
408 
409     assertThat(policy.checkAuthorization(OTHER_UID).getCode()).isEqualTo(Status.PERMISSION_DENIED.getCode());
410   }
411 
412   @Test
413   @Config(sdk = 21)
testIsProfileOwner_failsWhenNoPackagesForUid()414   public void testIsProfileOwner_failsWhenNoPackagesForUid() throws Exception {
415     policy = SecurityPolicies.isProfileOwner(appContext);
416 
417     assertThat(policy.checkAuthorization(OTHER_UID).getCode()).isEqualTo(Status.UNAUTHENTICATED.getCode());
418   }
419 
420   @Test
421   @Config(sdk = 19)
testIsProfileOwner_failsForSdkLevelTooLow()422   public void testIsProfileOwner_failsForSdkLevelTooLow() throws Exception {
423     PackageInfo info =
424         newBuilder().setPackageName(OTHER_UID_PACKAGE_NAME).setSignatures(SIG2).build();
425 
426     installPackages(OTHER_UID, info);
427 
428     policy = SecurityPolicies.isProfileOwner(appContext);
429 
430     assertThat(policy.checkAuthorization(OTHER_UID).getCode()).isEqualTo(Status.PERMISSION_DENIED.getCode());
431   }
432 
433   @Test
434   @Config(sdk = 30)
testIsProfileOwnerOnOrgOwned_succeedsForProfileOwnerOnOrgOwned()435   public void testIsProfileOwnerOnOrgOwned_succeedsForProfileOwnerOnOrgOwned() throws Exception {
436     PackageInfo info =
437         newBuilder().setPackageName(OTHER_UID_PACKAGE_NAME).setSignatures(SIG2).build();
438 
439     installPackages(OTHER_UID, info);
440     shadowOf(devicePolicyManager)
441         .setProfileOwner(new ComponentName(OTHER_UID_PACKAGE_NAME, "foo"));
442     shadowOf(devicePolicyManager).setOrganizationOwnedDeviceWithManagedProfile(true);
443 
444     policy = SecurityPolicies.isProfileOwnerOnOrganizationOwnedDevice(appContext);
445 
446     assertThat(policy.checkAuthorization(OTHER_UID).getCode()).isEqualTo(Status.OK.getCode());
447 
448   }
449 
450   @Test
451   @Config(sdk = 30)
testIsProfileOwnerOnOrgOwned_failsForProfileOwnerOnNonOrgOwned()452   public void testIsProfileOwnerOnOrgOwned_failsForProfileOwnerOnNonOrgOwned() throws Exception {
453     PackageInfo info =
454         newBuilder().setPackageName(OTHER_UID_PACKAGE_NAME).setSignatures(SIG2).build();
455 
456     installPackages(OTHER_UID, info);
457     shadowOf(devicePolicyManager)
458         .setProfileOwner(new ComponentName(OTHER_UID_PACKAGE_NAME, "foo"));
459     shadowOf(devicePolicyManager).setOrganizationOwnedDeviceWithManagedProfile(false);
460 
461     policy = SecurityPolicies.isProfileOwnerOnOrganizationOwnedDevice(appContext);
462 
463     assertThat(policy.checkAuthorization(OTHER_UID).getCode()).isEqualTo(Status.PERMISSION_DENIED.getCode());
464   }
465 
466   @Test
467   @Config(sdk = 21)
testIsProfileOwnerOnOrgOwned_failsForNotProfileOwner()468   public void testIsProfileOwnerOnOrgOwned_failsForNotProfileOwner() throws Exception {
469     PackageInfo info =
470         newBuilder().setPackageName(OTHER_UID_PACKAGE_NAME).setSignatures(SIG2).build();
471 
472     installPackages(OTHER_UID, info);
473 
474     policy = SecurityPolicies.isProfileOwnerOnOrganizationOwnedDevice(appContext);
475 
476     assertThat(policy.checkAuthorization(OTHER_UID).getCode()).isEqualTo(Status.PERMISSION_DENIED.getCode());
477   }
478 
479   @Test
480   @Config(sdk = 21)
testIsProfileOwnerOnOrgOwned_failsWhenNoPackagesForUid()481   public void testIsProfileOwnerOnOrgOwned_failsWhenNoPackagesForUid() throws Exception {
482     policy = SecurityPolicies.isProfileOwnerOnOrganizationOwnedDevice(appContext);
483 
484     assertThat(policy.checkAuthorization(OTHER_UID).getCode()).isEqualTo(Status.UNAUTHENTICATED.getCode());
485   }
486 
487   @Test
488   @Config(sdk = 29)
testIsProfileOwnerOnOrgOwned_failsForSdkLevelTooLow()489   public void testIsProfileOwnerOnOrgOwned_failsForSdkLevelTooLow() throws Exception {
490     PackageInfo info =
491         newBuilder().setPackageName(OTHER_UID_PACKAGE_NAME).setSignatures(SIG2).build();
492 
493     installPackages(OTHER_UID, info);
494 
495     policy = SecurityPolicies.isProfileOwner(appContext);
496 
497     assertThat(policy.checkAuthorization(OTHER_UID).getCode()).isEqualTo(Status.PERMISSION_DENIED.getCode());
498   }
499 
newBuilder()500   private static PackageInfoBuilder newBuilder() {
501     return new PackageInfoBuilder();
502   }
503 
504   private static class PackageInfoBuilder {
505     private String packageName;
506     private Signature[] signatures;
507     private final HashMap<String, Integer> permissions = new HashMap<>();
508 
setPackageName(String packageName)509     public PackageInfoBuilder setPackageName(String packageName) {
510       this.packageName = packageName;
511       return this;
512     }
513 
setPermission(String permissionName, int permissionFlag)514     public PackageInfoBuilder setPermission(String permissionName, int permissionFlag) {
515       this.permissions.put(permissionName, permissionFlag);
516       return this;
517     }
518 
setSignatures(Signature... signatures)519     public PackageInfoBuilder setSignatures(Signature... signatures) {
520       this.signatures = signatures;
521       return this;
522     }
523 
build()524     public PackageInfo build() {
525       checkState(this.packageName != null, "packageName is a mandatory field");
526 
527       PackageInfo packageInfo = new PackageInfo();
528 
529       packageInfo.packageName = this.packageName;
530 
531       if (this.signatures != null) {
532         packageInfo.signatures = this.signatures;
533       }
534 
535       if (!this.permissions.isEmpty()) {
536         String[] requestedPermissions =
537             this.permissions.keySet().toArray(new String[this.permissions.size()]);
538         int[] requestedPermissionsFlags = new int[requestedPermissions.length];
539 
540         for (int i = 0; i < requestedPermissions.length; i++) {
541           requestedPermissionsFlags[i] = this.permissions.get(requestedPermissions[i]);
542         }
543 
544         packageInfo.requestedPermissions = requestedPermissions;
545         packageInfo.requestedPermissionsFlags = requestedPermissionsFlags;
546       }
547 
548       return packageInfo;
549     }
550   }
551 
552   @Test
testAllOf_succeedsIfAllSecurityPoliciesAllowed()553   public void testAllOf_succeedsIfAllSecurityPoliciesAllowed() throws Exception {
554     policy = SecurityPolicies.allOf(SecurityPolicies.internalOnly());
555 
556     assertThat(policy.checkAuthorization(MY_UID).getCode()).isEqualTo(Status.OK.getCode());
557   }
558 
559   @Test
testAllOf_failsIfOneSecurityPoliciesNotAllowed()560   public void testAllOf_failsIfOneSecurityPoliciesNotAllowed() throws Exception {
561     policy =
562         SecurityPolicies.allOf(
563             SecurityPolicies.internalOnly(),
564             SecurityPolicies.permissionDenied("Not allowed SecurityPolicy"));
565 
566     assertThat(policy.checkAuthorization(MY_UID).getCode())
567         .isEqualTo(Status.PERMISSION_DENIED.getCode());
568     assertThat(policy.checkAuthorization(MY_UID).getDescription())
569         .contains("Not allowed SecurityPolicy");
570   }
571 
572   @Test
testAnyOf_succeedsIfAnySecurityPoliciesAllowed()573   public void testAnyOf_succeedsIfAnySecurityPoliciesAllowed() throws Exception {
574     RecordingPolicy recordingPolicy = new RecordingPolicy();
575     policy = SecurityPolicies.anyOf(SecurityPolicies.internalOnly(), recordingPolicy);
576 
577     assertThat(policy.checkAuthorization(MY_UID).getCode()).isEqualTo(Status.OK.getCode());
578     assertThat(recordingPolicy.numCalls.get()).isEqualTo(0);
579   }
580 
581   @Test
testAnyOf_failsIfNoSecurityPolicyIsAllowed()582   public void testAnyOf_failsIfNoSecurityPolicyIsAllowed() throws Exception {
583     policy =
584         SecurityPolicies.anyOf(
585             new SecurityPolicy() {
586               @Override
587               public Status checkAuthorization(int uid) {
588                 return Status.PERMISSION_DENIED.withDescription("Not allowed: first");
589               }
590             },
591             new SecurityPolicy() {
592               @Override
593               public Status checkAuthorization(int uid) {
594                 return Status.UNAUTHENTICATED.withDescription("Not allowed: second");
595               }
596             });
597 
598     assertThat(policy.checkAuthorization(MY_UID).getCode())
599         .isEqualTo(Status.PERMISSION_DENIED.getCode());
600     assertThat(policy.checkAuthorization(MY_UID).getDescription()).contains("Not allowed: first");
601     assertThat(policy.checkAuthorization(MY_UID).getDescription()).contains("Not allowed: second");
602   }
603 
604   private static final class RecordingPolicy extends SecurityPolicy {
605     private final AtomicInteger numCalls = new AtomicInteger(0);
606 
607     @Override
checkAuthorization(int uid)608     public Status checkAuthorization(int uid) {
609       numCalls.incrementAndGet();
610       return Status.OK;
611     }
612   }
613 
614   @Test
testHasSignatureSha256Hash_succeedsIfPackageNameAndSignatureHashMatch()615   public void testHasSignatureSha256Hash_succeedsIfPackageNameAndSignatureHashMatch()
616       throws Exception {
617     PackageInfo info =
618         newBuilder().setPackageName(OTHER_UID_PACKAGE_NAME).setSignatures(SIG2).build();
619     installPackages(OTHER_UID, info);
620 
621     policy =
622         SecurityPolicies.hasSignatureSha256Hash(
623             packageManager, OTHER_UID_PACKAGE_NAME, getSha256Hash(SIG2));
624 
625     // THEN UID for package that has SIG2 will be authorized
626     assertThat(policy.checkAuthorization(OTHER_UID).getCode()).isEqualTo(Status.OK.getCode());
627   }
628 
629   @Test
testHasSignatureSha256Hash_failsIfPackageNameDoesNotMatch()630   public void testHasSignatureSha256Hash_failsIfPackageNameDoesNotMatch() throws Exception {
631     PackageInfo info1 =
632         newBuilder().setPackageName(appContext.getPackageName()).setSignatures(SIG1).build();
633     installPackages(MY_UID, info1);
634 
635     PackageInfo info2 =
636         newBuilder()
637             .setPackageName(OTHER_UID_SAME_SIGNATURE_PACKAGE_NAME)
638             .setSignatures(SIG1)
639             .build();
640     installPackages(OTHER_UID_SAME_SIGNATURE, info2);
641 
642     policy =
643         SecurityPolicies.hasSignatureSha256Hash(
644             packageManager, appContext.getPackageName(), getSha256Hash(SIG1));
645 
646     // THEN UID for package that has SIG1 but different package name will not be authorized
647     assertThat(policy.checkAuthorization(OTHER_UID_SAME_SIGNATURE).getCode())
648         .isEqualTo(Status.PERMISSION_DENIED.getCode());
649   }
650 
651   @Test
testHasSignatureSha256Hash_failsIfSignatureHashDoesNotMatch()652   public void testHasSignatureSha256Hash_failsIfSignatureHashDoesNotMatch() throws Exception {
653     PackageInfo info =
654         newBuilder().setPackageName(OTHER_UID_PACKAGE_NAME).setSignatures(SIG2).build();
655     installPackages(OTHER_UID, info);
656 
657     policy =
658         SecurityPolicies.hasSignatureSha256Hash(
659             packageManager, OTHER_UID_PACKAGE_NAME, getSha256Hash(SIG1));
660 
661     // THEN UID for package that doesn't have SIG1 will not be authorized
662     assertThat(policy.checkAuthorization(OTHER_UID).getCode())
663         .isEqualTo(Status.PERMISSION_DENIED.getCode());
664   }
665 
666   @Test
testOneOfSignatureSha256Hash_succeedsIfPackageNameAndSignatureHashMatch()667   public void testOneOfSignatureSha256Hash_succeedsIfPackageNameAndSignatureHashMatch()
668       throws Exception {
669     PackageInfo info =
670         newBuilder().setPackageName(OTHER_UID_PACKAGE_NAME).setSignatures(SIG2).build();
671     installPackages(OTHER_UID, info);
672 
673     policy =
674         SecurityPolicies.oneOfSignatureSha256Hash(
675             packageManager, OTHER_UID_PACKAGE_NAME, ImmutableList.of(getSha256Hash(SIG2)));
676 
677     // THEN UID for package that has SIG2 will be authorized
678     assertThat(policy.checkAuthorization(OTHER_UID).getCode()).isEqualTo(Status.OK.getCode());
679   }
680 
681   @Test
testOneOfSignatureSha256Hash_succeedsIfPackageNameAndOneOfSignatureHashesMatch()682   public void testOneOfSignatureSha256Hash_succeedsIfPackageNameAndOneOfSignatureHashesMatch()
683       throws Exception {
684     PackageInfo info =
685         newBuilder().setPackageName(OTHER_UID_PACKAGE_NAME).setSignatures(SIG2).build();
686     installPackages(OTHER_UID, info);
687 
688     policy =
689         SecurityPolicies.oneOfSignatureSha256Hash(
690             packageManager,
691             OTHER_UID_PACKAGE_NAME,
692             ImmutableList.of(getSha256Hash(SIG1), getSha256Hash(SIG2)));
693 
694     // THEN UID for package that has SIG2 will be authorized
695     assertThat(policy.checkAuthorization(OTHER_UID).getCode()).isEqualTo(Status.OK.getCode());
696   }
697 
698   @Test
699   public void
testOneOfSignatureSha256Hash_failsIfPackageNameDoNotMatchAndOneOfSignatureHashesMatch()700   testOneOfSignatureSha256Hash_failsIfPackageNameDoNotMatchAndOneOfSignatureHashesMatch()
701       throws Exception {
702     PackageInfo info =
703         newBuilder().setPackageName(OTHER_UID_PACKAGE_NAME).setSignatures(SIG2).build();
704     installPackages(OTHER_UID, info);
705 
706     policy =
707         SecurityPolicies.oneOfSignatureSha256Hash(
708             packageManager,
709             appContext.getPackageName(),
710             ImmutableList.of(getSha256Hash(SIG1), getSha256Hash(SIG2)));
711 
712     // THEN UID for package that has SIG2 but different package name will not be authorized
713     assertThat(policy.checkAuthorization(OTHER_UID).getCode())
714         .isEqualTo(Status.PERMISSION_DENIED.getCode());
715   }
716 
717   @Test
testOneOfSignatureSha256Hash_failsIfPackageNameMatchAndOneOfSignatureHashesNotMatch()718   public void testOneOfSignatureSha256Hash_failsIfPackageNameMatchAndOneOfSignatureHashesNotMatch()
719       throws Exception {
720     PackageInfo info =
721         newBuilder()
722             .setPackageName(OTHER_UID_PACKAGE_NAME)
723             .setSignatures(new Signature("1234"))
724             .build();
725     installPackages(OTHER_UID, info);
726 
727     policy =
728         SecurityPolicies.oneOfSignatureSha256Hash(
729             packageManager,
730             appContext.getPackageName(),
731             ImmutableList.of(getSha256Hash(SIG1), getSha256Hash(SIG2)));
732 
733     // THEN UID for package that doesn't have SIG1 or SIG2 will not be authorized
734     assertThat(policy.checkAuthorization(OTHER_UID).getCode())
735         .isEqualTo(Status.PERMISSION_DENIED.getCode());
736   }
737 
getSha256Hash(Signature signature)738   private static byte[] getSha256Hash(Signature signature) {
739     return Hashing.sha256().hashBytes(signature.toByteArray()).asBytes();
740   }
741 }
742