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