blob: a955dbc3fa037c25d77aca0e720e17a7e679ddec [file] [log] [blame]
/*
* Copyright (C) 2019 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 com.android.cts.usespermissiondiffcertapp;
import static com.android.cts.usespermissiondiffcertapp.AccessPermissionWithDiffSigTest.PERM_URI_GRANTING;
import static com.android.cts.usespermissiondiffcertapp.Asserts.assertNoPersistedUriPermission;
import static com.android.cts.usespermissiondiffcertapp.Asserts.assertPersistedUriPermission;
import static com.android.cts.usespermissiondiffcertapp.Asserts.assertReadingClipAllowed;
import static com.android.cts.usespermissiondiffcertapp.Asserts.assertReadingClipNotAllowed;
import static com.android.cts.usespermissiondiffcertapp.Asserts.assertWritingClipAllowed;
import static com.android.cts.usespermissiondiffcertapp.Asserts.assertWritingClipNotAllowed;
import static com.android.cts.usespermissiondiffcertapp.Utils.grantClipUriPermission;
import static com.android.cts.usespermissiondiffcertapp.Utils.grantClipUriPermissionViaContext;
import static com.android.cts.usespermissiondiffcertapp.Utils.revokeClipUriPermissionViaContext;
import static junit.framework.Assert.fail;
import android.content.ClipData;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class UriGrantsTest {
static final String TAG = "UriGrantsTest";
private static Context getContext() {
return InstrumentationRegistry.getTargetContext();
}
static ClipData makeSingleClipData(Uri uri) {
return new ClipData("foo", new String[] { "foo/bar" },
new ClipData.Item(uri));
}
static ClipData makeMultiClipData(Uri uri) {
Uri grantClip1Uri = uri;
Uri grantClip2Uri = Uri.withAppendedPath(uri, "clip2");
Uri grantClip3Uri = Uri.withAppendedPath(uri, "clip3");
Uri grantClip4Uri = Uri.withAppendedPath(uri, "clip4");
Uri grantClip5Uri = Uri.withAppendedPath(uri, "clip5");
ClipData clip = new ClipData("foo", new String[] { "foo/bar" },
new ClipData.Item(grantClip1Uri));
clip.addItem(new ClipData.Item(grantClip2Uri));
// Intents in the ClipData should allow their data: and clip URIs
// to be granted, but only respect the grant flags of the top-level
// Intent.
clip.addItem(new ClipData.Item(new Intent(Intent.ACTION_VIEW, grantClip3Uri)));
Intent intent = new Intent(Intent.ACTION_VIEW, grantClip4Uri);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
clip.addItem(new ClipData.Item(intent));
intent = new Intent(Intent.ACTION_VIEW);
intent.setClipData(new ClipData("foo", new String[] { "foo/bar" },
new ClipData.Item(grantClip5Uri)));
clip.addItem(new ClipData.Item(intent));
return clip;
}
/**
* Validate behavior of persistable permission grants.
*/
@Test
public void testGrantPersistableUriPermission() {
final ContentResolver resolver = getContext().getContentResolver();
final Uri target = Uri.withAppendedPath(PERM_URI_GRANTING, "foo");
final ClipData clip = makeSingleClipData(target);
// Make sure we can't see the target
assertReadingClipNotAllowed(clip, "reading should have failed");
assertWritingClipNotAllowed(clip, "writing should have failed");
// Make sure we can't take a grant we don't have
try {
resolver.takePersistableUriPermission(target, Intent.FLAG_GRANT_READ_URI_PERMISSION);
fail("taking read should have failed");
} catch (SecurityException expected) {
}
// And since we were just installed, no persisted grants yet
assertNoPersistedUriPermission();
// Now, let's grant ourselves some access
ReceiveUriActivity.clearStarted();
grantClipUriPermission(clip, Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, false);
ReceiveUriActivity.waitForStart();
// We should now have reading access, even before taking the persistable
// grant. Persisted grants should still be empty.
assertReadingClipAllowed(clip);
assertWritingClipNotAllowed(clip, "writing should have failed");
assertNoPersistedUriPermission();
// Take the read grant and verify we have it!
long before = System.currentTimeMillis();
resolver.takePersistableUriPermission(target, Intent.FLAG_GRANT_READ_URI_PERMISSION);
long after = System.currentTimeMillis();
assertPersistedUriPermission(target, Intent.FLAG_GRANT_READ_URI_PERMISSION, before, after);
// Make sure we can't take a grant we don't have
try {
resolver.takePersistableUriPermission(target, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
fail("taking write should have failed");
} catch (SecurityException expected) {
}
// Launch again giving ourselves persistable read and write access
ReceiveUriActivity.clearNewIntent();
grantClipUriPermission(clip, Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION
| Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, false);
ReceiveUriActivity.waitForNewIntent();
// Previous persisted grant should be unchanged
assertPersistedUriPermission(target, Intent.FLAG_GRANT_READ_URI_PERMISSION, before, after);
// We should have both read and write; read is persisted, and write
// isn't persisted yet.
assertReadingClipAllowed(clip);
assertWritingClipAllowed(clip);
// Take again, but still only read; should just update timestamp
before = System.currentTimeMillis();
resolver.takePersistableUriPermission(target, Intent.FLAG_GRANT_READ_URI_PERMISSION);
after = System.currentTimeMillis();
assertPersistedUriPermission(target, Intent.FLAG_GRANT_READ_URI_PERMISSION, before, after);
// And take yet again, both read and write
before = System.currentTimeMillis();
resolver.takePersistableUriPermission(target,
Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
after = System.currentTimeMillis();
assertPersistedUriPermission(target,
Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
before, after);
// Now drop the persisted grant; write first, then read
resolver.releasePersistableUriPermission(target, Intent.FLAG_GRANT_READ_URI_PERMISSION);
assertPersistedUriPermission(target, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, before, after);
resolver.releasePersistableUriPermission(target, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
assertNoPersistedUriPermission();
// And even though we dropped the persistable grants, our activity is
// still running with the global grants (until reboot).
assertReadingClipAllowed(clip);
assertWritingClipAllowed(clip);
ReceiveUriActivity.finishCurInstanceSync();
}
/**
* Validate behavior of prefix permission grants.
*/
@Test
public void testGrantPrefixUriPermission() throws Exception {
final Uri target = Uri.withAppendedPath(PERM_URI_GRANTING, "foo1");
final Uri targetMeow = Uri.withAppendedPath(target, "meow");
final Uri targetMeowCat = Uri.withAppendedPath(targetMeow, "cat");
final ClipData clip = makeSingleClipData(target);
final ClipData clipMeow = makeSingleClipData(targetMeow);
final ClipData clipMeowCat = makeSingleClipData(targetMeowCat);
// Make sure we can't see the target
assertReadingClipNotAllowed(clip, "reading should have failed");
assertWritingClipNotAllowed(clip, "writing should have failed");
// Give ourselves prefix read access
ReceiveUriActivity.clearStarted();
grantClipUriPermission(clipMeow, Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_PREFIX_URI_PERMISSION, false);
ReceiveUriActivity.waitForStart();
// Verify prefix read access
assertReadingClipNotAllowed(clip, "reading should have failed");
assertReadingClipAllowed(clipMeow);
assertReadingClipAllowed(clipMeowCat);
assertWritingClipNotAllowed(clip, "writing should have failed");
assertWritingClipNotAllowed(clipMeow, "writing should have failed");
assertWritingClipNotAllowed(clipMeowCat, "writing should have failed");
// Now give ourselves exact write access
ReceiveUriActivity.clearNewIntent();
grantClipUriPermission(clip, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, false);
ReceiveUriActivity.waitForNewIntent();
// Verify we have exact write access, but not prefix write
assertReadingClipNotAllowed(clip, "reading should have failed");
assertReadingClipAllowed(clipMeow);
assertReadingClipAllowed(clipMeowCat);
assertWritingClipAllowed(clip);
assertWritingClipNotAllowed(clipMeow, "writing should have failed");
assertWritingClipNotAllowed(clipMeowCat, "writing should have failed");
ReceiveUriActivity.finishCurInstanceSync();
}
@Test
public void testGrantPersistablePrefixUriPermission() {
final ContentResolver resolver = getContext().getContentResolver();
final Uri target = Uri.withAppendedPath(PERM_URI_GRANTING, "foo2");
final Uri targetMeow = Uri.withAppendedPath(target, "meow");
final ClipData clip = makeSingleClipData(target);
final ClipData clipMeow = makeSingleClipData(targetMeow);
// Make sure we can't see the target
assertReadingClipNotAllowed(clip, "reading should have failed");
// Give ourselves prefix read access
ReceiveUriActivity.clearStarted();
grantClipUriPermission(clip, Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
| Intent.FLAG_GRANT_PREFIX_URI_PERMISSION, false);
ReceiveUriActivity.waitForStart();
// Verify prefix read access
assertReadingClipAllowed(clip);
assertReadingClipAllowed(clipMeow);
// Verify we can persist direct grant
long before = System.currentTimeMillis();
resolver.takePersistableUriPermission(target, Intent.FLAG_GRANT_READ_URI_PERMISSION);
long after = System.currentTimeMillis();
assertPersistedUriPermission(target, Intent.FLAG_GRANT_READ_URI_PERMISSION, before, after);
// But we can't take anywhere under the prefix
try {
resolver.takePersistableUriPermission(targetMeow,
Intent.FLAG_GRANT_READ_URI_PERMISSION);
fail("taking under prefix should have failed");
} catch (SecurityException expected) {
}
// Should still have access regardless of taking
assertReadingClipAllowed(clip);
assertReadingClipAllowed(clipMeow);
// And clean up our grants
resolver.releasePersistableUriPermission(target, Intent.FLAG_GRANT_READ_URI_PERMISSION);
assertNoPersistedUriPermission();
ReceiveUriActivity.finishCurInstanceSync();
}
/**
* Validate behavior of directly granting/revoking permission grants.
*/
@Test
public void testDirectGrantRevokeUriPermission() throws Exception {
final ContentResolver resolver = getContext().getContentResolver();
final Uri target = Uri.withAppendedPath(PERM_URI_GRANTING, "foo3");
final Uri targetMeow = Uri.withAppendedPath(target, "meow");
final Uri targetMeowCat = Uri.withAppendedPath(targetMeow, "cat");
final ClipData clip = makeSingleClipData(target);
final ClipData clipMeow = makeSingleClipData(targetMeow);
final ClipData clipMeowCat = makeSingleClipData(targetMeowCat);
// Make sure we can't see the target
assertReadingClipNotAllowed(clipMeow, "reading should have failed");
assertWritingClipNotAllowed(clipMeow, "writing should have failed");
// Give ourselves some grants:
// /meow/cat WRITE|PERSISTABLE
// /meow READ|PREFIX
// /meow WRITE
grantClipUriPermissionViaContext(targetMeowCat, Intent.FLAG_GRANT_WRITE_URI_PERMISSION
| Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
grantClipUriPermissionViaContext(targetMeow, Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
grantClipUriPermissionViaContext(targetMeow, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
long before = System.currentTimeMillis();
resolver.takePersistableUriPermission(targetMeowCat, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
long after = System.currentTimeMillis();
assertPersistedUriPermission(targetMeowCat, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, before, after);
// Verify they look good
assertReadingClipNotAllowed(clip, "reading should have failed");
assertReadingClipAllowed(clipMeow);
assertReadingClipAllowed(clipMeowCat);
assertWritingClipNotAllowed(clip, "writing should have failed");
assertWritingClipAllowed(clipMeow);
assertWritingClipAllowed(clipMeowCat);
// Revoke anyone with write under meow
revokeClipUriPermissionViaContext(targetMeow, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
// This should have nuked persisted permission at lower level, but it
// shoulnd't have touched our prefix read.
assertReadingClipNotAllowed(clip, "reading should have failed");
assertReadingClipAllowed(clipMeow);
assertReadingClipAllowed(clipMeowCat);
assertWritingClipNotAllowed(clip, "writing should have failed");
assertWritingClipNotAllowed(clipMeow, "writing should have failed");
assertWritingClipNotAllowed(clipMeowCat, "writing should have failed");
assertNoPersistedUriPermission();
// Revoking read at top of tree should nuke everything else
revokeClipUriPermissionViaContext(target, Intent.FLAG_GRANT_READ_URI_PERMISSION);
assertReadingClipNotAllowed(clip, "reading should have failed");
assertReadingClipNotAllowed(clipMeow, "reading should have failed");
assertReadingClipNotAllowed(clipMeowCat, "reading should have failed");
assertWritingClipNotAllowed(clip, "writing should have failed");
assertWritingClipNotAllowed(clipMeow, "writing should have failed");
assertWritingClipNotAllowed(clipMeowCat, "writing should have failed");
assertNoPersistedUriPermission();
}
/**
* Validate behavior of a direct permission grant, where the receiver of
* that permission revokes it.
*/
@Test
public void testDirectGrantReceiverRevokeUriPermission() throws Exception {
final ContentResolver resolver = getContext().getContentResolver();
final Uri target = Uri.withAppendedPath(PERM_URI_GRANTING, "foo3");
final Uri targetMeow = Uri.withAppendedPath(target, "meow");
final Uri targetMeowCat = Uri.withAppendedPath(targetMeow, "cat");
final ClipData clip = makeSingleClipData(target);
final ClipData clipMeow = makeSingleClipData(targetMeow);
final ClipData clipMeowCat = makeSingleClipData(targetMeowCat);
// Make sure we can't see the target
assertReadingClipNotAllowed(clipMeow, "reading should have failed");
assertWritingClipNotAllowed(clipMeow, "writing should have failed");
// Give ourselves some grants:
// /meow/cat WRITE|PERSISTABLE
// /meow READ|PREFIX
// /meow WRITE
grantClipUriPermissionViaContext(targetMeowCat, Intent.FLAG_GRANT_WRITE_URI_PERMISSION
| Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
grantClipUriPermissionViaContext(targetMeow, Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
grantClipUriPermissionViaContext(targetMeow, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
long before = System.currentTimeMillis();
resolver.takePersistableUriPermission(targetMeowCat, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
long after = System.currentTimeMillis();
assertPersistedUriPermission(targetMeowCat, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, before, after);
// Verify they look good
assertReadingClipNotAllowed(clip, "reading should have failed");
assertReadingClipAllowed(clipMeow);
assertReadingClipAllowed(clipMeowCat);
assertWritingClipNotAllowed(clip, "writing should have failed");
assertWritingClipAllowed(clipMeow);
assertWritingClipAllowed(clipMeowCat);
// Revoke anyone with write under meow
getContext().revokeUriPermission(targetMeow, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
// This should have nuked persisted permission at lower level, but it
// shoulnd't have touched our prefix read.
assertReadingClipNotAllowed(clip, "reading should have failed");
assertReadingClipAllowed(clipMeow);
assertReadingClipAllowed(clipMeowCat);
assertWritingClipNotAllowed(clip, "writing should have failed");
assertWritingClipNotAllowed(clipMeow, "writing should have failed");
assertWritingClipNotAllowed(clipMeowCat, "writing should have failed");
assertNoPersistedUriPermission();
// Revoking read at top of tree should nuke everything else
getContext().revokeUriPermission(target, Intent.FLAG_GRANT_READ_URI_PERMISSION);
assertReadingClipNotAllowed(clip, "reading should have failed");
assertReadingClipNotAllowed(clipMeow, "reading should have failed");
assertReadingClipNotAllowed(clipMeowCat, "reading should have failed");
assertWritingClipNotAllowed(clip, "writing should have failed");
assertWritingClipNotAllowed(clipMeow, "writing should have failed");
assertWritingClipNotAllowed(clipMeowCat, "writing should have failed");
assertNoPersistedUriPermission();
}
}