blob: d9998955c7d691fed3499484ae4c244ab73966d2 [file] [log] [blame]
/*
* Copyright (C) 2009 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.Asserts.assertContentUriAllowed;
import static com.android.cts.usespermissiondiffcertapp.Asserts.assertContentUriNotAllowed;
import static com.android.cts.usespermissiondiffcertapp.Asserts.assertReadingContentUriAllowed;
import static com.android.cts.usespermissiondiffcertapp.Asserts.assertReadingContentUriNotAllowed;
import static com.android.cts.usespermissiondiffcertapp.Asserts.assertWritingContentUriAllowed;
import static com.android.cts.usespermissiondiffcertapp.Asserts.assertWritingContentUriNotAllowed;
import static junit.framework.Assert.assertEquals;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.provider.CalendarContract;
import android.provider.ContactsContract;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
/**
* Tests that signature-enforced permissions cannot be accessed by apps signed
* with different certs than app that declares the permission.
*
* Accesses app cts/tests/appsecurity-tests/test-apps/PermissionDeclareApp/...
*/
@RunWith(AndroidJUnit4.class)
public class AccessPermissionWithDiffSigTest {
private static Context getContext() {
return InstrumentationRegistry.getTargetContext();
}
static final Uri PERM_URI = Uri.parse("content://ctspermissionwithsignature");
static final Uri PERM_URI_GRANTING = Uri.parse("content://ctspermissionwithsignaturegranting");
static final Uri PERM_URI_PATH = Uri.parse("content://ctspermissionwithsignaturepath");
static final Uri PERM_URI_PATH_RESTRICTING = Uri.parse(
"content://ctspermissionwithsignaturepathrestricting");
static final Uri PRIV_URI = Uri.parse("content://ctsprivateprovider");
static final Uri PRIV_URI_GRANTING = Uri.parse("content://ctsprivateprovidergranting");
static final String EXPECTED_MIME_TYPE = "got/theMIME";
static final Uri AMBIGUOUS_URI_COMPAT = Uri.parse("content://ctsambiguousprovidercompat");
static final String EXPECTED_MIME_TYPE_AMBIGUOUS = "got/theUnspecifiedMIME";
static final Uri AMBIGUOUS_URI = Uri.parse("content://ctsambiguousprovider");
static final Uri[] GRANTABLE = new Uri[] {
Uri.withAppendedPath(PERM_URI_GRANTING, "foo"),
Uri.withAppendedPath(PERM_URI_PATH, "foo"),
Uri.withAppendedPath(PRIV_URI_GRANTING, "foo"),
};
static final Uri[] NOT_GRANTABLE = new Uri[] {
Uri.withAppendedPath(PERM_URI, "bar"),
Uri.withAppendedPath(PERM_URI_GRANTING, "bar"),
Uri.withAppendedPath(PERM_URI_PATH, "bar"),
Uri.withAppendedPath(PRIV_URI, "bar"),
Uri.withAppendedPath(PRIV_URI_GRANTING, "bar"),
Uri.withAppendedPath(AMBIGUOUS_URI, "bar"),
CalendarContract.CONTENT_URI,
ContactsContract.AUTHORITY_URI,
};
static final int[] GRANTABLE_MODES = new int[] {
Intent.FLAG_GRANT_READ_URI_PERMISSION,
Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
};
static final int[] NOT_GRANTABLE_MODES = new int[] {
Intent.FLAG_GRANT_READ_URI_PERMISSION,
Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION,
Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION,
Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION,
Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION,
};
/**
* Test that the ctspermissionwithsignature content provider cannot be read,
* since this app lacks the required certs
*/
@Test
public void testReadProviderWithDiff() {
assertReadingContentUriNotAllowed(PERM_URI, null);
}
/**
* Test that the ctspermissionwithsignature content provider cannot be written,
* since this app lacks the required certs
*/
@Test
public void testWriteProviderWithDiff() {
assertWritingContentUriNotAllowed(PERM_URI, null);
}
/**
* Test that the ctsprivateprovider content provider cannot be read,
* since it is not exported from its app.
*/
@Test
public void testReadProviderWhenPrivate() {
assertReadingContentUriNotAllowed(PRIV_URI, "shouldn't read private provider");
}
/**
* Test that the ctsambiguousprovider content provider cannot be read,
* since it doesn't have an "exported=" line.
*/
@Test
public void testReadProviderWhenAmbiguous() {
assertReadingContentUriNotAllowed(AMBIGUOUS_URI, "shouldn't read ambiguous provider");
}
/**
* Old App Compatibility Test
*
* Test that the ctsambiguousprovidercompat content provider can be read for older
* API versions, because it didn't specify either exported=true or exported=false.
*/
@Test
public void testReadProviderWhenAmbiguousCompat() {
assertReadingContentUriAllowed(AMBIGUOUS_URI_COMPAT);
}
/**
* Old App Compatibility Test
*
* Test that the ctsambiguousprovidercompat content provider can be written for older
* API versions, because it didn't specify either exported=true or exported=false.
*/
@Test
public void testWriteProviderWhenAmbiguousCompat() {
assertWritingContentUriAllowed(AMBIGUOUS_URI_COMPAT);
}
/**
* Test that the ctsprivateprovider content provider cannot be written,
* since it is not exported from its app.
*/
@Test
public void testWriteProviderWhenPrivate() {
assertWritingContentUriNotAllowed(PRIV_URI, "shouldn't write private provider");
}
/**
* Test that the ctsambiguousprovider content provider cannot be written,
* since it doesn't have an exported= line.
*/
@Test
public void testWriteProviderWhenAmbiguous() {
assertWritingContentUriNotAllowed(AMBIGUOUS_URI, "shouldn't write ambiguous provider");
}
/**
* Verify that we can access paths outside the {@code path-permission}
* protections, which should only rely on {@code provider} permissions.
*/
@Test
public void testRestrictingProviderNoMatchingPath() {
assertReadingContentUriAllowed(PERM_URI_PATH_RESTRICTING);
assertWritingContentUriAllowed(PERM_URI_PATH_RESTRICTING);
// allowed by no top-level permission
final Uri test = PERM_URI_PATH_RESTRICTING.buildUpon().appendPath("fo").build();
assertReadingContentUriAllowed(test);
assertWritingContentUriAllowed(test);
}
/**
* Verify that paths under {@code path-permission} restriction aren't
* allowed, even though the {@code provider} requires no permissions.
*/
@Test
public void testRestrictingProviderMatchingPathDenied() {
// rejected by "foo" prefix
final Uri test1 = PERM_URI_PATH_RESTRICTING.buildUpon().appendPath("foo").build();
assertReadingContentUriNotAllowed(test1, null);
assertWritingContentUriNotAllowed(test1, null);
// rejected by "foo" prefix
final Uri test2 = PERM_URI_PATH_RESTRICTING.buildUpon()
.appendPath("foo").appendPath("ba").build();
assertReadingContentUriNotAllowed(test2, null);
assertWritingContentUriNotAllowed(test2, null);
}
/**
* Test that shady {@link Uri} are blocked by {@code path-permission}.
*/
@Test
public void testRestrictingProviderMatchingShadyPaths() {
assertContentUriAllowed(
Uri.parse("content://ctspermissionwithsignaturepathrestricting/"));
assertContentUriAllowed(
Uri.parse("content://ctspermissionwithsignaturepathrestricting//"));
assertContentUriAllowed(
Uri.parse("content://ctspermissionwithsignaturepathrestricting///"));
assertContentUriNotAllowed(
Uri.parse("content://ctspermissionwithsignaturepathrestricting/foo"), null);
assertContentUriNotAllowed(
Uri.parse("content://ctspermissionwithsignaturepathrestricting//foo"), null);
assertContentUriNotAllowed(
Uri.parse("content://ctspermissionwithsignaturepathrestricting///foo"), null);
assertContentUriNotAllowed(
Uri.parse("content://ctspermissionwithsignaturepathrestricting/foo//baz"), null);
}
/**
* Verify that at least one {@code path-permission} rule will grant access,
* even if the caller doesn't hold another matching {@code path-permission}.
*/
@Test
public void testRestrictingProviderMultipleMatchingPath() {
// allowed by narrow "foo/bar" prefix
final Uri test1 = PERM_URI_PATH_RESTRICTING.buildUpon()
.appendPath("foo").appendPath("bar").build();
assertReadingContentUriAllowed(test1);
assertWritingContentUriAllowed(test1);
// allowed by narrow "foo/bar" prefix
final Uri test2 = PERM_URI_PATH_RESTRICTING.buildUpon()
.appendPath("foo").appendPath("bar2").build();
assertReadingContentUriAllowed(test2);
assertWritingContentUriAllowed(test2);
}
@Test
public void testGetMimeTypePermission() {
// Precondition: no current access.
assertReadingContentUriNotAllowed(PERM_URI, "shouldn't read when starting test");
assertWritingContentUriNotAllowed(PERM_URI, "shouldn't write when starting test");
// All apps should be able to get MIME type regardless of permission.
assertEquals(getContext().getContentResolver().getType(PERM_URI), EXPECTED_MIME_TYPE);
}
@Test
public void testGetMimeTypePrivate() {
// Precondition: no current access.
assertReadingContentUriNotAllowed(PRIV_URI, "shouldn't read when starting test");
assertWritingContentUriNotAllowed(PRIV_URI, "shouldn't write when starting test");
// All apps should be able to get MIME type even if provider is private.
assertEquals(getContext().getContentResolver().getType(PRIV_URI), EXPECTED_MIME_TYPE);
}
@Test
public void testGetMimeTypeAmbiguous() {
// Precondition: no current access.
assertReadingContentUriNotAllowed(AMBIGUOUS_URI, "shouldn't read when starting test");
assertWritingContentUriNotAllowed(AMBIGUOUS_URI, "shouldn't write when starting test");
// All apps should be able to get MIME type even if provider is private.
assertEquals(getContext().getContentResolver().getType(AMBIGUOUS_URI), EXPECTED_MIME_TYPE);
}
/**
* Old App Compatibility Test
*
* We should be able to access the mime type of a content provider of an older
* application, even if that application didn't explicitly declare either
* exported=true or exported=false
*/
@Test
public void testGetMimeTypeAmbiguousCompat() {
// All apps should be able to get MIME type even if provider is private.
assertEquals(EXPECTED_MIME_TYPE_AMBIGUOUS,
getContext().getContentResolver().getType(AMBIGUOUS_URI_COMPAT));
}
}