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

Commit 76a9d9c0 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add TestablePermissons, which allows basic control"

parents 80059ffc d01cef91
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