Android M Content Provider Permissions - android

I have seen similar questions, but I think I'm running into Android M specific trouble.
I have two Android applications. One extends ContentProvider to manage a SQLiteDatabase. The other presents a GUI and reads/writes data from/to the Content Provider. The two applications work together successfully until I try to set permissions on the Content Provider.
I receive the following error message:
Caused by: java.lang.SecurityException: Permission Denial: opening
provider com.example.productkit.ProductKit from ProcessRecord{ce096cd
27369:com.example.myapplication/u0a60} (pid=27369, uid=10060) requires
com.example.productkit.permission.CONTENT_PROVIDER or
com.example.productkit.permission.CONTENT_PROVIDER
The AndroidManifest.xml file for the Content Provider looks like this:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.productkit">
<permission android:name="com.example.productkit.permission.CONTENT_PROVIDER"/>
<application>
<provider
android:name=".ProductKit"
android:authorities="com.example.productkit"
android:exported="true"
android:permission="com.example.productkit.permission.CONTENT_PROVIDER"/>
</application>
</manifest>
The AndroidManifest.xml file for the GUI application looks like this:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapplication">
<uses-permission android:name="com.example.productkit.permission.CONTENT_PROVIDER"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme">
<activity
android:name=".MainActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
My understanding is that the application needs to request permission(s) at run time with Android M. As an experiment, I've tried to do that with the following test code:
int hasPermission = checkSelfPermission("com.example.productkit.permission.CONTENT_PROVIDER");
if (hasPermission != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[] {"com.example.productkit.permission.CONTENT_PROVIDER"},
REQUEST_CODE_ASK_PERMISSIONS);
}
hasPermission = checkSelfPermission("com.example.productkit.permission.CONTENT_PROVIDER");
Unfortunately hasPermission does not equal PERMISSION_GRANTED following the call to requestPermissions().
If I use the same code to gain access to a built-in permission, like to the CAMERA, a dialog appears and I can grant permission to the application. That behavior does not happen for my Content Provider's permission.

Related

Defining your own permissions in android

I am trying make my own permission for android application.
For this my android manifest file looks like this.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.hp.happybirthday" >
<permission
android:name="com.example.hp.happybirthday.PERM"
android:description="#string/pdesc"
android:label="#string/CAREFUL"
/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme"
android:permission="com.example.hp.happybirthday.PERM">
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
The problem that I am facing is that I want to have my own permission associated with this application and hence i have added the following line as shown above under the application tag, so that only those activities have access to this app which possess my defined permission.
android:permission="com.example.hp.happybirthday.PERM"
But the problem is that when I try to run my app, the app whose manifest file I have declared, it shows the error app is not installed.
But when I remove the above mentioned line, it works, but then any activity will have access to this app which I do not want.
when I try to run my app, the app whose manifest file I have declared, it shows the error app is not installed
That is because the home screen is an app, and the home screen does not hold your custom permission. Hence, the home screen cannot start your launcher activity.
then any activity will have access to this app which I do not want
First, custom permissions do not work all that well.
Second, permissions are usually applied at a finer granularity than "this app". You only secure those components that need the security, and you leave public other components, like the launcher activity.
It looks like you've defined the permission, and set it to be required... but you haven't actually granted it to your own app. Add a uses-permission tag

Android Permissions - Best Practices

I have two Android Applications, a permission provider and a requester.
The provider has the below manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.permissionprovider"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />
<permission android:description="#string/permission_desc"
android:icon="#drawable/ic_launcher"
android:label="some permission"
android:name="com.example.permissionprovider.CUSTOM"
android:protectionLevel="normal" />
<!-- is the below tag required in the provider?-->
<uses-permission android:name="com.example.permissionprovider.CUSTOM"/>
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.example.permissionprovider.MainActivity"
android:permission="com.example.permissionprovider.CUSTOM"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
I hope it is wrong to set permissions to a launchable activity as the launcher won't have permissions to launch this activity.Is that correct?
Should the provider's manifest declare that the provider application needs the permission - com.example.permissionprovider.CUSTOM , or is it not required as the permission is defined in the same manifest?
Now I have the requester app which has the below manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.permissionrequester"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />
<uses-permission android:name="com.example.permissionprovider.CUSTOM"/>
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.example.permissionrequester.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
and the Requester tries to start the provider's activity.
Intent i;
PackageManager manager = getPackageManager();
try {
i = manager.getLaunchIntentForPackage("com.example.permissionprovider");
if (i == null)
throw new PackageManager.NameNotFoundException();
i.addCategory(Intent.CATEGORY_LAUNCHER);
startActivity(i);
} catch (PackageManager.NameNotFoundException e) {
} }
If the provider app was installed first followed by the requester, then the requester will be able to launch the provider's Activity, but this doesn't happen if it's the requester which is installed first. How to get around this?
I hope it is wrong to set permissions to a launchable activity as the launcher won't have permissions to launch this activity.Is that correct?
Correct, the launcher will be incapable of starting that activity. However, it will still appear in the launcher, and therefore the user will get frustrated when they cannot start up your app.
Should the provider's manifest declare that the provider application needs the permission - com.example.permissionprovider.CUSTOM , or is it not required as the permission is defined in the same manifest?
You can define the <permission> in both apps, to deal with your last problem:
If the provider app was installed first followed by the requester, then the requester will be able to launch the provider's Activity, but this doesn't happen if it's the requester which is installed first. How to get around this?
Define the <permission> in both apps.
Also, if you are publishing both apps, and no third parties should be using your provider, please use a signature-level permission, not a normal-one. This will prevent anyone other than you from writing an app that can successfully hold the permission.

Enable communication between two Android apps via custom permissions

One of my Android applications needs some features that are "dangerous" when it comes to permissions. They require some permissions such as "Internet access" which are critical in combination with private data.
This is why I want to create a separate "Add-on", i.e. a second app that provides these permission-critical features. So if users want them, they can install the add-on, but the main app will still work without those permissions.
Using a sharedUserId would obviously be the easiest solution, but adding this afterwards, when lots of users use the app already, could cause serious problems. Wouldn't this mean that the app can't access its own data any longer?
So I have to choose another approach. ContentProviders are something that I try to avoid, because they're too complex for this simple need in my opinion.
I thought custom permissions could solve the issue. Can they? I've added the following permission declaration to both the main app as well as the add-on as a child to the manifest tag in AndroidManifest.xml:
<permission
android:name="com.my.package.ADDON"
android:label="#string/permission_title"
android:description="#string/permission_description"
android:permissionGroup="android.permission-group.PERSONAL_INFO"
android:protectionLevel="signature" />
Furthermore, both manifest files have got this part now:
<uses-permission android:name="com.my.package.ADDON"></uses-permission>
The add-on app includes an IntentService that has the following attribute now:
android:permission="com.my.package.ADDON"
Shouldn't this do the job so that I can call the add-on's IntentService from my main app via this code?
Intent addonIntent = new Intent();
addonIntent.setClassName("com.my.package", "com.my.package.MyService");
startService(addonIntent);
Unfortunately, this call always fails with the following exception:
E/AndroidRuntime(16721): java.lang.SecurityException: Not allowed to start service Intent { cmp=com.mypackage.addon/.MyService } without permission com.mypackage.permission.ADDON
What did I do wrong? Thank you very much in advance!
Addition #1 - Add-on manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1"
android:versionName="1.0"
package="com.mypackage.addon">
<uses-sdk android:minSdkVersion="8" />
<permission
android:name="com.mypackage.permission.ADDON"
android:label="#string/permission_title"
android:description="#string/permission_description"
android:permissionGroup="android.permission-group.PERSONAL_INFO"
android:protectionLevel="signature" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:permission="com.mypackage.permission.ADDON"
android:exported="true">
<service
android:enabled="true"
android:name=".MyService" />
</application>
</manifest>
Addition #2 - main app manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1"
android:versionName="1.0"
package="com.mypackage.mainapp">
<uses-sdk android:minSdkVersion="8" />
<permission
android:name="com.mypackage.permission.ADDON"
android:label="#string/permission_title"
android:description="#string/permission_description"
android:permissionGroup="android.permission-group.PERSONAL_INFO"
android:protectionLevel="signature" />
<uses-permission android:name="com.mypackage.permission.ADDON"></uses-permission>
<application android:icon="#drawable/ic_launcher" android:label="#string/app_name" android:name="MyApp">
<activity android:name=".MainActivity" android:launchMode="singleTask" android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Wouldn't this mean that the app can't access its own data any longer?
Correct.
I've added the following permission
I would dump the permission-group, as that should not be necessary.
Furthermore, both manifest files have got this part now
Only the one calling your IntentService might need that.
Shouldn't this do the job so that I can call the add-on's IntentService from my main app via this code?
Not if that IntentService is not exported. Make sure that your IntentService either has an <intent-filter> or android:exported="true". I would recommend going the <intent-filter> route, so you can declare and use a custom action string, so you get away from hard-coding package and class names in the client app.
Here is a directory with two sample projects using this basic approach, though in my case the communications are based on a secured ContentProvider rather than a secured IntentService. The concept is the same, though, and so with these minor tweaks, I would expect what you are doing to work just fine.

AndroidTestCase - assertActivityRequiresPermission and assertReadingContentUriRequiresPermission

hoping for some help with the methods assertActivityRequiresPermission and assertReadingContentUriRequiresPermission. It's not behaving the way I thought it will and I'm not seeing where I went wrong.
My understanding is that both activities and providers can be protected by adding android:permission to their respective tags ( and ) in AndroidManifest.xml. To declare that a client activity has the required permission to start and activity or work with a provider, we declare under the tag in what I believe to be at a 'package' level.
So to test how the assert methods in AndroidTestCase works I set up a HelloWorld project and a project to test HelloWorld. This is the manifest for HelloWorld.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.helloandroid"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="8" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<application android:icon="#drawable/icon" android:label="#string/app_name">
<activity android:name=".HelloAndroidActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".RecipientActivity"
android:label="#string/app_name"
android:permission="android.permission.RECEIVE_SMS" >
</activity>
</application>
</manifest>
I have RecipientActivity protected by RECEIVE_SMS, so I declare using RECEIVE_SMS so that HelloAndroidActivity is able to start RecipientActivity.
Now in my test class,
public class TestRecipientActivity extends AndroidTestCase {
public void testPermissions() {
String packageName = "com.example.helloandroid";
String className = packageName + ".RecipientActivity";
String permission = android.Manifest.permission.RECEIVE_SMS;
assertActivityRequiresPermission(packageName, className, permission);
}
public void testContactsPermissions() {
final Uri URI = ContactsContract.AUTHORITY_URI;
final String permission = android.Manifest.permission.READ_CONTACTS;
assertReadingContentUriRequiresPermission(URI, permission);
}
}
Results?
testPermissions() fails with 'AssertionFailError: expected security exception', meaning RecipientActivity is started successfully with no SecurityException thrown.
testContactsPermissions() passed without throwing any exception although I do not have define anywhere.
Can anyone explain why I'm getting the above results? Thanks!
You asked this question long time ago and I don't know if you have already solved it.
I am learning Unit-Testing in Android and I had the same problem. At the beginning I thought that the method assertActivityRequiresPermission() tests the permissions declared in < uses-permission >, but then I realized that this method only test if there is a specific permission associated to the activity passed as parameter.
You are associating the same permission to the < uses-permission > and < activity > tags. The point is that the assert works if you delete the permission from < uses-permission >. I think the problem is that this assert is expecting a SecurityException caused because it can't launch the activity without the permission, but you are using that permission in the manifest.xml, so the exception is not thrown.

Android securityException and user contacts

I have am wrighting an android app and as a part of the app I would like the user to be able to see, select,and modify the user contacts. My main activity extends the TabActivity for usability reasons(from the users side). So in a tab i would like to show user contacts i have done that with this code: mTabHost.addTab(mTabHost.newTabSpec("tab_test2").setIndicator("Contacts").setContent(new Intent(Intent.ACTION_PICK, People.CONTENT_URI)));
that uses the default phone contact activity. my android manifest is: `
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.READ_OWNER_DATA"/>
<application android:icon="#drawable/icon" android:theme="#android:style/Theme.NoTitleBar">
<activity android:name=".WaveCally"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".streamer"
android:label="#string/stream">
</activity>
</application>
<uses-sdk android:minSdkVersion="4" />
` but I keep getting a security exception in my log and the activity crashes. any ideas?
Also as I mentioned I would like to modify the contacts (mostly add some extra fields), to do that I have to get the contantprovider and in every contact add the extra fields? would those extra fields be available if I then pick a contact from the above mentioned activity?
You need to declare in the application Manifest that your application is going to access the Contacts. (android.permission.READ_CONTACTS)
This is what you need to do:
http://developer.android.com/guide/topics/manifest/uses-permission-element.html
Basically, add the following line in your app manifest (right after opening the manifest tag):
<uses-permission android:name="android.permission.READ_CONTACTS" />

Categories

Resources