1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.cts.usespermissiondiffcertapp;
18 
19 import static com.android.cts.usespermissiondiffcertapp.AccessPermissionWithDiffSigTest.PERM_URI_GRANTING;
20 import static com.android.cts.usespermissiondiffcertapp.Asserts.assertNoPersistedUriPermission;
21 import static com.android.cts.usespermissiondiffcertapp.Asserts.assertPersistedUriPermission;
22 import static com.android.cts.usespermissiondiffcertapp.Asserts.assertReadingClipAllowed;
23 import static com.android.cts.usespermissiondiffcertapp.Asserts.assertReadingClipNotAllowed;
24 import static com.android.cts.usespermissiondiffcertapp.Asserts.assertWritingClipAllowed;
25 import static com.android.cts.usespermissiondiffcertapp.Asserts.assertWritingClipNotAllowed;
26 import static com.android.cts.usespermissiondiffcertapp.Utils.grantClipUriPermissionViaActivity;
27 import static com.android.cts.usespermissiondiffcertapp.Utils.grantClipUriPermissionViaContext;
28 import static com.android.cts.usespermissiondiffcertapp.Utils.revokeClipUriPermissionViaContext;
29 
30 import static junit.framework.Assert.fail;
31 
32 import android.content.ClipData;
33 import android.content.ContentResolver;
34 import android.content.Context;
35 import android.content.Intent;
36 import android.net.Uri;
37 
38 import androidx.test.InstrumentationRegistry;
39 import androidx.test.runner.AndroidJUnit4;
40 
41 import org.junit.Test;
42 import org.junit.runner.RunWith;
43 
44 @RunWith(AndroidJUnit4.class)
45 public class UriGrantsTest {
46     static final String TAG = "UriGrantsTest";
47 
getContext()48     private static Context getContext() {
49         return InstrumentationRegistry.getTargetContext();
50     }
51 
makeSingleClipData(Uri uri)52     static ClipData makeSingleClipData(Uri uri) {
53         return new ClipData("foo", new String[] { "foo/bar" },
54                 new ClipData.Item(uri));
55     }
56 
makeMultiClipData(Uri uri)57     static ClipData makeMultiClipData(Uri uri) {
58         Uri grantClip1Uri = uri;
59         Uri grantClip2Uri = Uri.withAppendedPath(uri, "clip2");
60         Uri grantClip3Uri = Uri.withAppendedPath(uri, "clip3");
61         Uri grantClip4Uri = Uri.withAppendedPath(uri, "clip4");
62         Uri grantClip5Uri = Uri.withAppendedPath(uri, "clip5");
63         ClipData clip = new ClipData("foo", new String[] { "foo/bar" },
64                 new ClipData.Item(grantClip1Uri));
65         clip.addItem(new ClipData.Item(grantClip2Uri));
66         // Intents in the ClipData should allow their data: and clip URIs
67         // to be granted, but only respect the grant flags of the top-level
68         // Intent.
69         clip.addItem(new ClipData.Item(new Intent(Intent.ACTION_VIEW, grantClip3Uri)));
70         Intent intent = new Intent(Intent.ACTION_VIEW, grantClip4Uri);
71         intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
72                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
73         clip.addItem(new ClipData.Item(intent));
74         intent = new Intent(Intent.ACTION_VIEW);
75         intent.setClipData(new ClipData("foo", new String[] { "foo/bar" },
76                 new ClipData.Item(grantClip5Uri)));
77         clip.addItem(new ClipData.Item(intent));
78         return clip;
79     }
80 
81     /**
82      * Validate behavior of persistable permission grants.
83      */
84     @Test
testGrantPersistableUriPermission()85     public void testGrantPersistableUriPermission() {
86         final ContentResolver resolver = getContext().getContentResolver();
87 
88         final Uri target = Uri.withAppendedPath(PERM_URI_GRANTING, "foo");
89         final ClipData clip = makeSingleClipData(target);
90 
91         // Make sure we can't see the target
92         assertReadingClipNotAllowed(clip, "reading should have failed");
93         assertWritingClipNotAllowed(clip, "writing should have failed");
94 
95         // Make sure we can't take a grant we don't have
96         try {
97             resolver.takePersistableUriPermission(target, Intent.FLAG_GRANT_READ_URI_PERMISSION);
98             fail("taking read should have failed");
99         } catch (SecurityException expected) {
100         }
101 
102         // And since we were just installed, no persisted grants yet
103         assertNoPersistedUriPermission();
104 
105         // Now, let's grant ourselves some access
106         ReceiveUriActivity.clearStarted();
107         grantClipUriPermissionViaActivity(clip, Intent.FLAG_GRANT_READ_URI_PERMISSION
108                 | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
109         ReceiveUriActivity.waitForStart();
110 
111         // We should now have reading access, even before taking the persistable
112         // grant. Persisted grants should still be empty.
113         assertReadingClipAllowed(clip);
114         assertWritingClipNotAllowed(clip, "writing should have failed");
115         assertNoPersistedUriPermission();
116 
117         // Take the read grant and verify we have it!
118         long before = System.currentTimeMillis();
119         resolver.takePersistableUriPermission(target, Intent.FLAG_GRANT_READ_URI_PERMISSION);
120         long after = System.currentTimeMillis();
121         assertPersistedUriPermission(target, Intent.FLAG_GRANT_READ_URI_PERMISSION, before, after);
122 
123         // Make sure we can't take a grant we don't have
124         try {
125             resolver.takePersistableUriPermission(target, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
126             fail("taking write should have failed");
127         } catch (SecurityException expected) {
128         }
129 
130         // Launch again giving ourselves persistable read and write access
131         ReceiveUriActivity.clearNewIntent();
132         grantClipUriPermissionViaActivity(clip, Intent.FLAG_GRANT_READ_URI_PERMISSION
133                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
134                 | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
135         ReceiveUriActivity.waitForNewIntent();
136 
137         // Previous persisted grant should be unchanged
138         assertPersistedUriPermission(target, Intent.FLAG_GRANT_READ_URI_PERMISSION, before, after);
139 
140         // We should have both read and write; read is persisted, and write
141         // isn't persisted yet.
142         assertReadingClipAllowed(clip);
143         assertWritingClipAllowed(clip);
144 
145         // Take again, but still only read; should just update timestamp
146         before = System.currentTimeMillis();
147         resolver.takePersistableUriPermission(target, Intent.FLAG_GRANT_READ_URI_PERMISSION);
148         after = System.currentTimeMillis();
149         assertPersistedUriPermission(target, Intent.FLAG_GRANT_READ_URI_PERMISSION, before, after);
150 
151         // And take yet again, both read and write
152         before = System.currentTimeMillis();
153         resolver.takePersistableUriPermission(target,
154                 Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
155         after = System.currentTimeMillis();
156         assertPersistedUriPermission(target,
157                 Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
158                 before, after);
159 
160         // Now drop the persisted grant; write first, then read
161         resolver.releasePersistableUriPermission(target, Intent.FLAG_GRANT_READ_URI_PERMISSION);
162         assertPersistedUriPermission(target, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, before, after);
163         resolver.releasePersistableUriPermission(target, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
164         assertNoPersistedUriPermission();
165 
166         // And even though we dropped the persistable grants, our activity is
167         // still running with the global grants (until reboot).
168         assertReadingClipAllowed(clip);
169         assertWritingClipAllowed(clip);
170 
171         ReceiveUriActivity.finishCurInstanceSync();
172     }
173 
174     /**
175      * Validate behavior of prefix permission grants.
176      */
177     @Test
testGrantPrefixUriPermission()178     public void testGrantPrefixUriPermission() throws Exception {
179         final Uri target = Uri.withAppendedPath(PERM_URI_GRANTING, "foo1");
180         final Uri targetMeow = Uri.withAppendedPath(target, "meow");
181         final Uri targetMeowCat = Uri.withAppendedPath(targetMeow, "cat");
182 
183         final ClipData clip = makeSingleClipData(target);
184         final ClipData clipMeow = makeSingleClipData(targetMeow);
185         final ClipData clipMeowCat = makeSingleClipData(targetMeowCat);
186 
187         // Make sure we can't see the target
188         assertReadingClipNotAllowed(clip, "reading should have failed");
189         assertWritingClipNotAllowed(clip, "writing should have failed");
190 
191         // Give ourselves prefix read access
192         ReceiveUriActivity.clearStarted();
193         grantClipUriPermissionViaActivity(clipMeow, Intent.FLAG_GRANT_READ_URI_PERMISSION
194                 | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
195         ReceiveUriActivity.waitForStart();
196 
197         // Verify prefix read access
198         assertReadingClipNotAllowed(clip, "reading should have failed");
199         assertReadingClipAllowed(clipMeow);
200         assertReadingClipAllowed(clipMeowCat);
201         assertWritingClipNotAllowed(clip, "writing should have failed");
202         assertWritingClipNotAllowed(clipMeow, "writing should have failed");
203         assertWritingClipNotAllowed(clipMeowCat, "writing should have failed");
204 
205         // Now give ourselves exact write access
206         ReceiveUriActivity.clearNewIntent();
207         grantClipUriPermissionViaActivity(clip, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
208         ReceiveUriActivity.waitForNewIntent();
209 
210         // Verify we have exact write access, but not prefix write
211         assertReadingClipNotAllowed(clip, "reading should have failed");
212         assertReadingClipAllowed(clipMeow);
213         assertReadingClipAllowed(clipMeowCat);
214         assertWritingClipAllowed(clip);
215         assertWritingClipNotAllowed(clipMeow, "writing should have failed");
216         assertWritingClipNotAllowed(clipMeowCat, "writing should have failed");
217 
218         ReceiveUriActivity.finishCurInstanceSync();
219     }
220 
221     @Test
testGrantPersistablePrefixUriPermission()222     public void testGrantPersistablePrefixUriPermission() {
223         final ContentResolver resolver = getContext().getContentResolver();
224 
225         final Uri target = Uri.withAppendedPath(PERM_URI_GRANTING, "foo2");
226         final Uri targetMeow = Uri.withAppendedPath(target, "meow");
227 
228         final ClipData clip = makeSingleClipData(target);
229         final ClipData clipMeow = makeSingleClipData(targetMeow);
230 
231         // Make sure we can't see the target
232         assertReadingClipNotAllowed(clip, "reading should have failed");
233 
234         // Give ourselves prefix read access
235         ReceiveUriActivity.clearStarted();
236         grantClipUriPermissionViaActivity(clip, Intent.FLAG_GRANT_READ_URI_PERMISSION
237                 | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
238                 | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
239         ReceiveUriActivity.waitForStart();
240 
241         // Verify prefix read access
242         assertReadingClipAllowed(clip);
243         assertReadingClipAllowed(clipMeow);
244 
245         // Verify we can persist direct grant
246         long before = System.currentTimeMillis();
247         resolver.takePersistableUriPermission(target, Intent.FLAG_GRANT_READ_URI_PERMISSION);
248         long after = System.currentTimeMillis();
249         assertPersistedUriPermission(target, Intent.FLAG_GRANT_READ_URI_PERMISSION, before, after);
250 
251         // But we can't take anywhere under the prefix
252         try {
253             resolver.takePersistableUriPermission(targetMeow,
254                     Intent.FLAG_GRANT_READ_URI_PERMISSION);
255             fail("taking under prefix should have failed");
256         } catch (SecurityException expected) {
257         }
258 
259         // Should still have access regardless of taking
260         assertReadingClipAllowed(clip);
261         assertReadingClipAllowed(clipMeow);
262 
263         // And clean up our grants
264         resolver.releasePersistableUriPermission(target, Intent.FLAG_GRANT_READ_URI_PERMISSION);
265         assertNoPersistedUriPermission();
266 
267         ReceiveUriActivity.finishCurInstanceSync();
268     }
269 
270     /**
271      * Validate behavior of directly granting/revoking permission grants.
272      */
273     @Test
testDirectGrantRevokeUriPermission()274     public void testDirectGrantRevokeUriPermission() throws Exception {
275         final ContentResolver resolver = getContext().getContentResolver();
276 
277         final Uri target = Uri.withAppendedPath(PERM_URI_GRANTING, "foo3");
278         final Uri targetMeow = Uri.withAppendedPath(target, "meow");
279         final Uri targetMeowCat = Uri.withAppendedPath(targetMeow, "cat");
280 
281         final ClipData clip = makeSingleClipData(target);
282         final ClipData clipMeow = makeSingleClipData(targetMeow);
283         final ClipData clipMeowCat = makeSingleClipData(targetMeowCat);
284 
285         // Make sure we can't see the target
286         assertReadingClipNotAllowed(clipMeow, "reading should have failed");
287         assertWritingClipNotAllowed(clipMeow, "writing should have failed");
288 
289         // Give ourselves some grants:
290         // /meow/cat  WRITE|PERSISTABLE
291         // /meow      READ|PREFIX
292         // /meow      WRITE
293         grantClipUriPermissionViaContext(targetMeowCat, Intent.FLAG_GRANT_WRITE_URI_PERMISSION
294                 | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
295         grantClipUriPermissionViaContext(targetMeow, Intent.FLAG_GRANT_READ_URI_PERMISSION
296                 | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
297         grantClipUriPermissionViaContext(targetMeow, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
298 
299         long before = System.currentTimeMillis();
300         resolver.takePersistableUriPermission(targetMeowCat, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
301         long after = System.currentTimeMillis();
302         assertPersistedUriPermission(targetMeowCat, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, before, after);
303 
304         // Verify they look good
305         assertReadingClipNotAllowed(clip, "reading should have failed");
306         assertReadingClipAllowed(clipMeow);
307         assertReadingClipAllowed(clipMeowCat);
308         assertWritingClipNotAllowed(clip, "writing should have failed");
309         assertWritingClipAllowed(clipMeow);
310         assertWritingClipAllowed(clipMeowCat);
311 
312         // Revoke anyone with write under meow
313         revokeClipUriPermissionViaContext(targetMeow, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
314 
315         // This should have nuked persisted permission at lower level, but it
316         // shoulnd't have touched our prefix read.
317         assertReadingClipNotAllowed(clip, "reading should have failed");
318         assertReadingClipAllowed(clipMeow);
319         assertReadingClipAllowed(clipMeowCat);
320         assertWritingClipNotAllowed(clip, "writing should have failed");
321         assertWritingClipNotAllowed(clipMeow, "writing should have failed");
322         assertWritingClipNotAllowed(clipMeowCat, "writing should have failed");
323         assertNoPersistedUriPermission();
324 
325         // Revoking read at top of tree should nuke everything else
326         revokeClipUriPermissionViaContext(target, Intent.FLAG_GRANT_READ_URI_PERMISSION);
327         assertReadingClipNotAllowed(clip, "reading should have failed");
328         assertReadingClipNotAllowed(clipMeow, "reading should have failed");
329         assertReadingClipNotAllowed(clipMeowCat, "reading should have failed");
330         assertWritingClipNotAllowed(clip, "writing should have failed");
331         assertWritingClipNotAllowed(clipMeow, "writing should have failed");
332         assertWritingClipNotAllowed(clipMeowCat, "writing should have failed");
333         assertNoPersistedUriPermission();
334     }
335 
336     /**
337      * Validate behavior of a direct permission grant, where the receiver of
338      * that permission revokes it.
339      */
340     @Test
testDirectGrantReceiverRevokeUriPermission()341     public void testDirectGrantReceiverRevokeUriPermission() throws Exception {
342         final ContentResolver resolver = getContext().getContentResolver();
343 
344         final Uri target = Uri.withAppendedPath(PERM_URI_GRANTING, "foo3");
345         final Uri targetMeow = Uri.withAppendedPath(target, "meow");
346         final Uri targetMeowCat = Uri.withAppendedPath(targetMeow, "cat");
347 
348         final ClipData clip = makeSingleClipData(target);
349         final ClipData clipMeow = makeSingleClipData(targetMeow);
350         final ClipData clipMeowCat = makeSingleClipData(targetMeowCat);
351 
352         // Make sure we can't see the target
353         assertReadingClipNotAllowed(clipMeow, "reading should have failed");
354         assertWritingClipNotAllowed(clipMeow, "writing should have failed");
355 
356         // Give ourselves some grants:
357         // /meow/cat  WRITE|PERSISTABLE
358         // /meow      READ|PREFIX
359         // /meow      WRITE
360         grantClipUriPermissionViaContext(targetMeowCat, Intent.FLAG_GRANT_WRITE_URI_PERMISSION
361                 | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
362         grantClipUriPermissionViaContext(targetMeow, Intent.FLAG_GRANT_READ_URI_PERMISSION
363                 | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
364         grantClipUriPermissionViaContext(targetMeow, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
365 
366         long before = System.currentTimeMillis();
367         resolver.takePersistableUriPermission(targetMeowCat, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
368         long after = System.currentTimeMillis();
369         assertPersistedUriPermission(targetMeowCat, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, before, after);
370 
371         // Verify they look good
372         assertReadingClipNotAllowed(clip, "reading should have failed");
373         assertReadingClipAllowed(clipMeow);
374         assertReadingClipAllowed(clipMeowCat);
375         assertWritingClipNotAllowed(clip, "writing should have failed");
376         assertWritingClipAllowed(clipMeow);
377         assertWritingClipAllowed(clipMeowCat);
378 
379         // Revoke anyone with write under meow
380         getContext().revokeUriPermission(targetMeow, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
381 
382         // This should have nuked persisted permission at lower level, but it
383         // shoulnd't have touched our prefix read.
384         assertReadingClipNotAllowed(clip, "reading should have failed");
385         assertReadingClipAllowed(clipMeow);
386         assertReadingClipAllowed(clipMeowCat);
387         assertWritingClipNotAllowed(clip, "writing should have failed");
388         assertWritingClipNotAllowed(clipMeow, "writing should have failed");
389         assertWritingClipNotAllowed(clipMeowCat, "writing should have failed");
390         assertNoPersistedUriPermission();
391 
392         // Revoking read at top of tree should nuke everything else
393         getContext().revokeUriPermission(target, Intent.FLAG_GRANT_READ_URI_PERMISSION);
394         assertReadingClipNotAllowed(clip, "reading should have failed");
395         assertReadingClipNotAllowed(clipMeow, "reading should have failed");
396         assertReadingClipNotAllowed(clipMeowCat, "reading should have failed");
397         assertWritingClipNotAllowed(clip, "writing should have failed");
398         assertWritingClipNotAllowed(clipMeow, "writing should have failed");
399         assertWritingClipNotAllowed(clipMeowCat, "writing should have failed");
400         assertNoPersistedUriPermission();
401     }
402 }
403