web-dev-qa-db-fra.com

Autorisations personnalisées Android - Guimauve

Background

Historiquement, les autorisations Android personnalisées étaient un fouillis et dépendaient de l'ordre d'installation , qui était connu pour exposait des vulnérabilités .

Avant API 21, il existait une solution de contournement selon laquelle la déclaration de l'autorisation personnalisée d'une autre application dans votre manifeste donnait l'autorisation ... Cependant, depuis l'API 21, une seule application peut déclarer une autorisation personnalisée et l'installation d'une autre application déclarant cette même permission sera empêchée.

Les alternatives sont de réinstaller l'application nécessitant l'autorisation, afin qu'elles soient détectées par le système, mais que n'est pas une bonne expérience utilisateur . Ou vérifiez au moment de l'exécution les autorisations de l'application appelante, mais ce n'est pas sans ses défauts théoriques .

Problème

Depuis Android Marshmallow (6.0 - API 23), une application doit demander l’autorisation de l’utilisateur, pour utiliser sa propre autorisation personnalisée . Une autorisation personnalisée déclarée n'est pas automatiquement accordée.

Cela semble étrange, étant donné qu’une seule application peut maintenant le déclarer.

Répliquer

Déclarez l'autorisation personnalisée et un BroadcastReceiver dans le manifeste.

<permission
    Android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"
    Android:description="@string/control_description"
    Android:icon="@mipmap/ic_launcher"
    Android:label="@string/control_label"
    Android:protectionLevel="normal or dangerous"/>

<uses-permission
    Android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"/>

// etc

<receiver
    Android:name="com.example.app.MyBroadcastReceiver"
    Android:permission="com.example.app.permission.CONTROL_EXAMPLE_APP">
    <intent-filter Android:priority="999">
        <action Android:name="com.example.app.REQUEST_RECEIVER"/>
    </intent-filter>
</receiver>

A partir d'une application tierce, déclarez qu'elle utilise l'autorisation personnalisée dans le manifeste (et l'acceptez via une boîte de dialogue ou les paramètres) et appelez:

    final Intent intent = new Intent("com.example.app.REQUEST_RECEIVER");

    context.sendOrderedBroadcast(intent, "com.example.app.permission.CONTROL_EXAMPLE_APP", new BroadcastReceiver() {
        @Override
        public void onReceive(final Context context, final Intent intent) {

        // getResultCode();

        }
    }, null, Activity.RESULT_CANCELED, null, null);

Le résultat retournera ANNULÉ et le journal affichera:

system_process W/BroadcastQueue: refus d'autorisation: intention de réception { act = com.example.app.REQUEST_RECEIVER flg = 0x10 (comporte des extras)} à com.example.app/.MyBroadcastReceiver requiert com.example.app.permission.CONTROL_EXAMPLE_APP en raison de l'expéditeur com.example.thirdparty

Si j'utilise la boîte de dialogue standard ActivityCompat.requestPermissions() pour permettre à l'utilisateur d'accepter l'autorisation, le récepteur, comme on peut s'y attendre, fonctionne correctement.

Question

Ce comportement est-il attendu? Ou ai-je en quelque sorte oublié quelque chose?

Il semblerait ridicule de parler de dialogue

L'application Example App demande l'autorisation d'utiliser Example App

Et cela peut effectivement concerner l'utilisateur, en lui fournissant une telle requête absurde.

Je peux bien sûr modifier la description et le nom de l'autorisation, en quelque chose qu'ils accepteraient, tel que 'communiquer avec d'autres applications installées', mais avant de soupirer et d'adopter cette approche, je pensais poser cette question.

Note

L'exemple de la diffusion ordonnée consiste à reproduire le problème. Mon application utilise d'autres implémentations de fournisseurs de contenu et un service lié. Ce n’est pas une implémentation alternative dont j’ai besoin, c’est une confirmation du problème.

Merci d'avoir lu jusqu'ici.

Edit: Pour clarifier, pour d'autres implémentations, telles que la déclaration d'une autorisation sur un service (qui serait plus simple à répliquer), l'autorisation personnalisée déclarée est automatiquement accordée.

30
brandall

Si j'ai bien compris, vous avez essayé de faire la chose suivante (du moins, c'est comme ça que j'ai pu reproduire votre problème):

  1. Vous déclarez votre nouvelle autorisation personnalisée dans la première application (appelons-la F)

    <permission
        Android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"
        Android:description="@string/control_description"
        Android:icon="@mipmap/ic_launcher"
        Android:label="@string/control_label"
        Android:protectionLevel="normal or dangerous"/>
    
  2. Vous définissez que votre application F utilise l'autorisation com.example.app.permission.CONTROL_EXAMPLE_APP. C'est juste comme le dit la ligne directrice.

    <uses-permission
        Android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"/>
    
  3. Vous déclarez votre récepteur de diffusion personnalisé dans votre application F. Pour communiquer avec cette émission, votre application (quelle que soit l'application, F ou une autre application) doit obtenir votre permission personnalisée.

    <receiver
        Android:name="com.example.app.MyBroadcastReceiver"
        Android:permission="com.example.app.permission.CONTROL_EXAMPLE_APP">
        <intent-filter Android:priority="999">
            <action Android:name="com.example.app.REQUEST_RECEIVER"/>
        </intent-filter>
    </receiver>
    
  4. Vous définissez que votre deuxième application (appelons-la S) utilise l'autorisation com.example.app.permission.CONTROL_EXAMPLE_APP. Parce que vous voulez autoriser S app à envoyer des messages diffusés au récepteur F app.

    <uses-permission
        Android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"/>
    
  5. Enfin, vous essayez d’envoyer un message à diffusion générale à partir de votre application S en utilisant ce code.

    final Intent intent = new Intent("com.example.app.REQUEST_RECEIVER");
    context.sendOrderedBroadcast(intent, "com.example.app.permission.CONTROL_EXAMPLE_APP", new BroadcastReceiver() {
            @Override
            public void onReceive(final Context context, final Intent intent) {
                // getResultCode();
            }
        }, null, Activity.RESULT_CANCELED, null, null);
    

    Et, ceci est important , vous avez accordé la permission à votre application S, mais vous n’avez pas accordé la permission à votre application F.

    En conséquence, votre récepteur de radiodiffusion déclaré dans l'application F n'a rien reçu.

  6. Après avoir accordé la permission à votre application F (notez que maintenant S et F ont accordé votre permission personnalisée), tout fonctionne correctement. Le récepteur de diffusion déclaré dans l'application F a reçu un message de S app.

J'imagine que c'est un comportement correct, parce que ce doc nous dit:

Notez que, dans cet exemple, l'autorisation DEBIT_ACCT n'est pas seulement Déclarée avec l'élément, son utilisation est également demandée avec l'élément . Vous devez en demander l'utilisation pour que D'autres composants de l'application puissent lancer l'activité protégée, , Même si la protection est imposée par l'application elle-même.

Et les applications qui déclarent une autorisation doivent également demander la même autorisation pour communiquer avec elles-mêmes.

En conséquence, l’API Android 23 doit avoir l’accès pour pouvoir utiliser d’abord votre formulaire de permission. Et nous devons obtenir 2 autorisations accordées, d'abord à partir de l'application F (car guidline l'indique comme tel) et ensuite de l'application S (car nous avons juste besoin d'obtenir un accès).

Mais je n'ai pas compris votre prochain point:

Il semblerait ridicule de parler de dialogue

L'application Example App demande l'autorisation d'utiliser Example App

Mon API 23 native pour Android m'affiche quelque chose comme ça:

L'application Example App veut 

1
Igor Tyulkanov

Je pense que le problème dans votre exemple est que vous exigez explicitement que les deux vos autorisations se voient accorder l'autorisation personnalisée.

Cette partie nécessite que l'application com.example.thirdparty dispose de l'autorisation suivante:

<receiver
    Android:name="com.example.app.MyBroadcastReceiver"
    Android:permission="com.example.app.permission.CONTROL_EXAMPLE_APP">

Et cette partie nécessite que l'application com.example.app ait également l'autorisation:

context.sendOrderedBroadcast(intent, "com.example.app.permission.CONTROL_EXAMPLE_APP", ...

Vous dites que vous n'avez pas ce problème lorsque vous utilisez un service. Je ne sais pas exactement comment vous utilisez le service, mais si vous le déclarez simplement comme ceci:

<service
    Android:name="com.example.app.MyService"
    Android:permission="com.example.app.permission.CONTROL_EXAMPLE_APP">

puis liez-le comme ceci:

context.bindService(serviceIntent, mServiceConnection, ...

alors c'est suffisant si com.example.thirdparty a l'autorisation accordée, alors que com.example.app n'a pas besoin de l'avoir.

En d'autres termes, je pense que ce problème est inhérent à la conception, et la différence que vous voyez entre le comportement de diffusion et le service est due au fait que dans le cas de diffusion, vous demandez spécifiquement que com.example.app dispose de l'autorisation personnalisée, alors que dans le cas de service que vous n'avez pas.

J'espère que je n'ai pas mal compris votre problème. Si tel est le cas, faites-le moi savoir et je supprimerai cette réponse.

0
Michal Dvorak

Je ne pense pas qu'il soit tout à fait vrai qu'une autorisation personnalisée déclarée ne soit pas automatiquement accordée à l'application. Lorsque le niveau de protection de l'autorisation personnalisée est "normal" ou "signature", il est alors accordé au moment de l'installation. Sinon, si le niveau de protection est "dangereux", il s'agit alors d'une autorisation d'exécution et fonctionne comme toutes les autres autorisations dangereuses: vous devrez demander à l'utilisateur d'autoriser l'autorisation à l'application.

0
Alice Van Der Land