Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d01cef91 authored by Jason Monk's avatar Jason Monk
Browse files

Add TestablePermissons, which allows basic control

Test: runtest --path frameworks/base/tests/testables
Change-Id: I8db323cfc26f592e2e002c9328ab97bc130d559b
parent 4d51f445
Loading
Loading
Loading
Loading
+155 −0
Original line number Diff line number Diff line
@@ -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() {
+80 −0
Original line number Diff line number Diff line
/*
 * 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();
        }
    }
}
+90 −0
Original line number Diff line number Diff line
/*
 * 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, "");
    }

}
 No newline at end of file