Merge "Add TestablePermissons, which allows basic control"

This commit is contained in:
TreeHugger Robot
2017-12-08 16:46:08 +00:00
committed by Android (Google) Code Review
3 changed files with 325 additions and 0 deletions

View File

@@ -25,6 +25,7 @@ import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
import android.os.UserHandle;
@@ -69,6 +70,7 @@ public class TestableContext extends ContextWrapper implements TestRule {
private LeakCheck.Tracker mService;
private LeakCheck.Tracker mComponent;
private TestableResources mTestableResources;
private TestablePermissions mTestablePermissions;
public TestableContext(Context base) {
this(base, null);
@@ -302,6 +304,159 @@ public class TestableContext extends ContextWrapper implements TestRule {
super.unregisterComponentCallbacks(callback);
}
public TestablePermissions getTestablePermissions() {
if (mTestablePermissions == null) {
mTestablePermissions = new TestablePermissions();
}
return mTestablePermissions;
}
@Override
public int checkCallingOrSelfPermission(String permission) {
if (mTestablePermissions != null && mTestablePermissions.wantsCall(permission)) {
return mTestablePermissions.check(permission);
}
return super.checkCallingOrSelfPermission(permission);
}
@Override
public int checkCallingPermission(String permission) {
if (mTestablePermissions != null && mTestablePermissions.wantsCall(permission)) {
return mTestablePermissions.check(permission);
}
return super.checkCallingPermission(permission);
}
@Override
public int checkPermission(String permission, int pid, int uid) {
if (mTestablePermissions != null && mTestablePermissions.wantsCall(permission)) {
return mTestablePermissions.check(permission);
}
return super.checkPermission(permission, pid, uid);
}
@Override
public int checkPermission(String permission, int pid, int uid, IBinder callerToken) {
if (mTestablePermissions != null && mTestablePermissions.wantsCall(permission)) {
return mTestablePermissions.check(permission);
}
return super.checkPermission(permission, pid, uid, callerToken);
}
@Override
public int checkSelfPermission(String permission) {
if (mTestablePermissions != null && mTestablePermissions.wantsCall(permission)) {
return mTestablePermissions.check(permission);
}
return super.checkSelfPermission(permission);
}
@Override
public void enforceCallingOrSelfPermission(String permission, String message) {
if (mTestablePermissions != null && mTestablePermissions.wantsCall(permission)) {
mTestablePermissions.enforce(permission);
} else {
super.enforceCallingOrSelfPermission(permission, message);
}
}
@Override
public void enforceCallingPermission(String permission, String message) {
if (mTestablePermissions != null && mTestablePermissions.wantsCall(permission)) {
mTestablePermissions.enforce(permission);
} else {
super.enforceCallingPermission(permission, message);
}
}
@Override
public void enforcePermission(String permission, int pid, int uid, String message) {
if (mTestablePermissions != null && mTestablePermissions.wantsCall(permission)) {
mTestablePermissions.enforce(permission);
} else {
super.enforcePermission(permission, pid, uid, message);
}
}
@Override
public int checkCallingOrSelfUriPermission(Uri uri, int modeFlags) {
if (mTestablePermissions != null && mTestablePermissions.wantsCall(uri)) {
return mTestablePermissions.check(uri, modeFlags);
}
return super.checkCallingOrSelfUriPermission(uri, modeFlags);
}
@Override
public int checkCallingUriPermission(Uri uri, int modeFlags) {
if (mTestablePermissions != null && mTestablePermissions.wantsCall(uri)) {
return mTestablePermissions.check(uri, modeFlags);
}
return super.checkCallingUriPermission(uri, modeFlags);
}
@Override
public void enforceCallingOrSelfUriPermission(Uri uri, int modeFlags, String message) {
if (mTestablePermissions != null && mTestablePermissions.wantsCall(uri)) {
mTestablePermissions.enforce(uri, modeFlags);
} else {
super.enforceCallingOrSelfUriPermission(uri, modeFlags, message);
}
}
@Override
public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
if (mTestablePermissions != null && mTestablePermissions.wantsCall(uri)) {
return mTestablePermissions.check(uri, modeFlags);
}
return super.checkUriPermission(uri, pid, uid, modeFlags);
}
@Override
public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags, IBinder callerToken) {
if (mTestablePermissions != null && mTestablePermissions.wantsCall(uri)) {
return mTestablePermissions.check(uri, modeFlags);
}
return super.checkUriPermission(uri, pid, uid, modeFlags, callerToken);
}
@Override
public int checkUriPermission(Uri uri, String readPermission, String writePermission, int pid,
int uid, int modeFlags) {
if (mTestablePermissions != null && mTestablePermissions.wantsCall(uri)) {
return mTestablePermissions.check(uri, modeFlags);
}
return super.checkUriPermission(uri, readPermission, writePermission, pid, uid, modeFlags);
}
@Override
public void enforceCallingUriPermission(Uri uri, int modeFlags, String message) {
if (mTestablePermissions != null && mTestablePermissions.wantsCall(uri)) {
mTestablePermissions.enforce(uri, modeFlags);
} else {
super.enforceCallingUriPermission(uri, modeFlags, message);
}
}
@Override
public void enforceUriPermission(Uri uri, int pid, int uid, int modeFlags, String message) {
if (mTestablePermissions != null && mTestablePermissions.wantsCall(uri)) {
mTestablePermissions.enforce(uri, modeFlags);
} else {
super.enforceUriPermission(uri, pid, uid, modeFlags, message);
}
}
@Override
public void enforceUriPermission(Uri uri, String readPermission, String writePermission,
int pid, int uid, int modeFlags, String message) {
if (mTestablePermissions != null && mTestablePermissions.wantsCall(uri)) {
mTestablePermissions.enforce(uri, modeFlags);
} else {
super.enforceUriPermission(uri, readPermission, writePermission, pid, uid, modeFlags,
message);
}
}
@Override
public Statement apply(Statement base, Description description) {
return new TestWatcher() {

View File

@@ -0,0 +1,80 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package android.testing;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.util.ArrayMap;
/**
* Simple class for simulating basic permission states for tests.
*
* All enforce* and check* calls on TestableContext are considered the same
* and routed through the same check here. If more fine-grained control is
* required, then either a sub-class or spy on TestableContext is recommended.
*/
public class TestablePermissions {
private final ArrayMap<String, Integer> mPermissions = new ArrayMap<>();
private final ArrayMap<Uri, Integer> mUris = new ArrayMap<>();
/**
* Sets the return value for checkPermission* calls on TestableContext
* for a specific permission value. For all enforcePermission* calls
* they will throw a security exception if value != PERMISSION_GRANTED.
*/
public void setPermission(String permission, int value) {
mPermissions.put(permission, value);
}
/**
* Sets the return value for checkUriPermission* calls on TestableContext
* for a specific permission value. For all enforceUriPermission* calls
* they will throw a security exception if value != PERMISSION_GRANTED.
*/
public void setPermission(Uri uri, int value) {
// TODO: Support modeFlags
mUris.put(uri, value);
}
boolean wantsCall(String permission) {
return mPermissions.containsKey(permission);
}
boolean wantsCall(Uri uri) {
return mUris.containsKey(uri);
}
int check(String permission) {
return mPermissions.get(permission);
}
int check(Uri uri, int modeFlags) {
// TODO: Support modeFlags
return mUris.get(uri);
}
public void enforce(String permission) {
if (check(permission) != PackageManager.PERMISSION_GRANTED) {
throw new SecurityException();
}
}
public void enforce(Uri uri, int modeFlags) {
if (check(uri, modeFlags) != PackageManager.PERMISSION_GRANTED) {
throw new SecurityException();
}
}
}

View File

@@ -0,0 +1,90 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package android.testing;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static org.junit.Assert.assertEquals;
import android.Manifest.permission;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.testing.TestableLooper.RunWithLooper;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class TestablePermissionsTest {
private static final Uri URI_1 = Uri.parse("content://my.authority/path1");
private static final Uri URI_2 = Uri.parse("content://my.authority/path2");
@Rule
public TestableContext mContext = new TestableContext(InstrumentationRegistry.getContext());
@Test
public void testCheck() {
mContext.getTestablePermissions().setPermission(permission.INTERACT_ACROSS_USERS,
PERMISSION_GRANTED);
mContext.getTestablePermissions().setPermission(permission.INTERACT_ACROSS_USERS_FULL,
PERMISSION_DENIED);
assertEquals(PERMISSION_GRANTED,
mContext.checkPermission(permission.INTERACT_ACROSS_USERS, 0, 0));
assertEquals(PERMISSION_DENIED,
mContext.checkPermission(permission.INTERACT_ACROSS_USERS_FULL, 0, 0));
}
@Test
public void testCheckUri() {
mContext.getTestablePermissions().setPermission(URI_1, PERMISSION_GRANTED);
mContext.getTestablePermissions().setPermission(URI_2, PERMISSION_DENIED);
assertEquals(PERMISSION_GRANTED, mContext.checkUriPermission(URI_1, 0, 0, 0));
assertEquals(PERMISSION_DENIED, mContext.checkUriPermission(URI_2, 0, 0, 0));
}
@Test
public void testEnforceNoException() {
mContext.getTestablePermissions().setPermission(permission.INTERACT_ACROSS_USERS,
PERMISSION_GRANTED);
mContext.enforceCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS, "");
}
@Test(expected = SecurityException.class)
public void testEnforceWithException() {
mContext.getTestablePermissions().setPermission(permission.INTERACT_ACROSS_USERS,
PERMISSION_DENIED);
mContext.enforceCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS, "");
}
@Test
public void testEnforceUriNoException() {
mContext.getTestablePermissions().setPermission(URI_1, PERMISSION_GRANTED);
mContext.enforceUriPermission(URI_1, 0, 0, 0, "");
}
@Test(expected = SecurityException.class)
public void testEnforceUriWithException() {
mContext.getTestablePermissions().setPermission(URI_1, PERMISSION_DENIED);
mContext.enforceUriPermission(URI_1, 0, 0, 0, "");
}
}