2

J'écris un processus dorsal en Java qui usurpera l'identité d'un utilisateur et ajouter/supprimer des documents sur leur Google Drive.401 Erreur non autorisée lors de l'utilisation d'un compte serveur pour usurper l'identité d'un utilisateur afin d'accéder à leur Google Drive

Le compte du serveur semble s'authentifier correctement mais lorsque j'essaye d'usurper l'identité d'un utilisateur, j'obtiens un 401 Unauthorized error. S'il vous plaît voir ci-dessous pour plus de détails.

Configuration

J'ai configuré le compte du serveur comme suit:

  • a créé un projet sous API Google et activé API Google Drive
  • créé un compte de service appelé [email protected] .gserviceaccount.com, définissez le rôle en tant qu'Acteur de compte de service et attribuez-lui la délégation à l'échelle du domaine. Il a ID client 110xxxxxxxxx342
  • je télécharger le fichier clé P12

J'ai configuré le domaine en utilisant l'écran Gérer l'accès client API pour autoriser 110xxxxxxxxx342 d'avoir la portée: https://www.googleapis.com/auth/drive.

Le service d'assistance Google a examiné ma configuration et m'a donné son feu vert.

Mon code ressemble alors comme suit:

package com.dcm.sharingdocuments; 

import java.io.File; 
import java.io.IOException; 
import java.util.Arrays; 
import java.util.Iterator; 
import java.util.List; 
import java.util.Set; 
import java.util.Map.Entry; 

import com.google.api.client.auth.oauth2.TokenErrorResponse; 
import com.google.api.client.auth.oauth2.TokenResponseException; 
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; 
import com.google.api.client.http.HttpTransport; 
import com.google.api.client.http.javanet.NetHttpTransport; 
import com.google.api.client.json.jackson2.JacksonFactory; 
import com.google.api.services.drive.Drive; 
import com.google.api.services.drive.DriveScopes; 
import com.google.api.services.drive.model.FileList; 

public class SharingDocumentsTest3 { 

    private static final String SERVICE_ACCOUNT_EMAIL = " [email protected]"; 

    public static Drive getDriveService(String userEmail) throws Exception { 

     File keyFile = new File("E:\\Projects\\Workspace\\Sharing Documents\\authentication\\AnotherTestKeyFile.p12"); 

     HttpTransport httpTransport = new NetHttpTransport(); 
     JacksonFactory jsonFactory = new JacksonFactory(); 

     List<String> SCOPES = Arrays.asList(DriveScopes.DRIVE_METADATA_READONLY); 

     GoogleCredential credential = null; 

     if (userEmail == null) { 

      credential = new GoogleCredential.Builder().setTransport(httpTransport).setJsonFactory(jsonFactory) 
        .setServiceAccountId(SERVICE_ACCOUNT_EMAIL).setServiceAccountScopes(SCOPES) 
        .setServiceAccountPrivateKeyFromP12File(keyFile).build(); 

      credential.refreshToken(); 

     } else { 

      credential = new GoogleCredential.Builder().setTransport(httpTransport).setJsonFactory(jsonFactory) 
        .setServiceAccountId(SERVICE_ACCOUNT_EMAIL).setServiceAccountScopes(SCOPES) 
        .setServiceAccountPrivateKeyFromP12File(keyFile).setServiceAccountUser(userEmail).build(); 

      credential.refreshToken(); 

     } 

     Drive service = new Drive.Builder(httpTransport, jsonFactory, null).setHttpRequestInitializer(credential) 
       .build(); 

     return service; 

    } 

    public static void main(String[] args) { 

     SharingDocumentsTest3 sdt3 = new SharingDocumentsTest3(); 

     sdt3.execute(); 

    } 

    private void execute() { 

     try { 

      Drive service = getDriveService(null); 

      Drive services = getDriveService("[email protected]"); 

      displayFiles(services); 

     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

    } 

    private void displayFiles(Drive service) throws Exception { 

     FileList result = service.files().list().setPageSize(10).execute(); 
     List<com.google.api.services.drive.model.File> files = result.getFiles(); 

     if (files == null || files.size() == 0) { 

      System.out.println("No files found."); 

     } else { 

      System.out.println("Files:"); 
      for (com.google.api.services.drive.model.File file : files) { 
       Set<Entry<String, Object>> entries = file.entrySet(); 

       Iterator<Entry<String, Object>> it = entries.iterator(); 

       while (it.hasNext()) { 
        Entry<String, Object> entry = it.next(); 
        String key = entry.getKey(); 
        Object value = entry.getValue(); 

        if (value instanceof String) { 
         System.out.println("\tKey = " + key + ", Value = " + (String) value); 
        } else { 
         System.out.println("\tKey = " + key + ", Value = " + value.toString()); 
        } 

       } 

       System.out.printf("%s (%s)\n", file.getName(), file.getId()); 
      } 
     } 
    } 
} 

Quand je lance le code comme ci-dessus est, je reçois l'erreur:

Mar 29, 2017 9:55:27 AM com.google.api.client.googleapis.services.AbstractGoogleClient <init> 
    WARNING: Application name is not set. Call Builder#setApplicationName. 
    com.google.api.client.auth.oauth2.TokenResponseException: 401 Unauthorized 
     at com.google.api.client.auth.oauth2.TokenResponseException.from(TokenResponseException.java:105) 
     at com.google.api.client.auth.oauth2.TokenRequest.executeUnparsed(TokenRequest.java:287) 
     at com.google.api.client.auth.oauth2.TokenRequest.execute(TokenRequest.java:307) 
     at com.google.api.client.googleapis.auth.oauth2.GoogleCredential.executeRefreshToken(GoogleCredential.java:384) 
     at com.google.api.client.auth.oauth2.Credential.refreshToken(Credential.java:489) 
     at com.dcm.sharingdocuments.SharingDocumentsTest3.getDriveService(SharingDocumentsTest3.java:50) 
     at com.dcm.sharingdocuments.SharingDocumentsTest3.execute(SharingDocumentsTest3.java:75) 
     at com.dcm.sharingdocuments.SharingDocumentsTest3.main(SharingDocumentsTest3.java:65) 

Ainsi, le code échoue à credential.refreshToken() lorsque J'ai mis le setServiceAccountUser. Il semble avoir actualisé le jeton avec succès quand je ne le fais pas. J'ai essayé différentes combinaisons de ce code - par ex. a commenté les lignes refreshToken(), a commenté la ligne getDriveService (null) - mais chaque fois que j'essaie d'utiliser/rafraîchir les informations d'identification obtenues pour l'utilisateur emprunté, j'obtiens l'erreur 401 Unauthorized.

Si je modifie le code de sorte que le lecteur obtenu par getDriveService (null) soit passé à DisplayFiles (...), je reçois un fichier appelé "Getting Started". Il semble donc que l'autorisation de compte de service fonctionne et que Google a ajouté son fichier par défaut au Drive pour le compte du serveur.

J'utilise des fichiers google-*1.22.0.jar et Java 1.8 au terme du code ci-dessus

Le problème que je pense est la façon dont je l'ai configuré le domaine ou la façon dont je suis en train de se faire passer pour l'utilisateur, mais mon code ressemble autant Des exemples sur le Web et le support Google semblent indiquer que j'ai configuré le domaine correctement. Tout ce que vous pouvez suggérer comme une résolution ou la prochaine étape serait très appréciée!

+0

Vérifiez la question suivante http://stackoverflow.com/questions/33602347/using-google-drive-api-from-a- Java-application où cela semble fonctionner. – Konrad

+0

Bonjour Konrad, merci beaucoup d'avoir répondu si rapidement. J'ai examiné la question, mais le problème de l'utilisateur est résolu en supprimant setServiceAccountUser (...), sans usurper l'identité d'un utilisateur. C'est ce que je vis aussi. Le code s'exécute à condition que je n'inclue pas setServiceAccountUser (...) mais j'ai besoin d'inclure cette méthode pour emprunter l'identité d'un utilisateur et avoir accès à ses fichiers. –

+0

1. Vous devriez laisser la bibliothèque du client s'occuper de rafraîchir votre accès. Ces comptes et services n'ont pas de jetons d'actualisation. 2. DriveScopes.DRIVE_METADATA_READONLY <- accès en lecture seule 3. démarrage rapide du compte de service https://developers.google.com/identity/protocols/OAuth2ServiceAccount – DaImTo

Répondre

0

J'ai été bloqué sur ce problème pendant longtemps et j'ai finalement trouvé mon problème. Il y a un bug dans la console d'administration "Gérer l'accès client API" ...

Vous devez indiquer le "Client ID" (par exemple 110xxxxxxxxx342) pour le nom du client et PAS le "Service Account ID" (celui qui ressemble à un email).Maintenant, their documentation is correct, et ils disent dans la documentation pour utiliser l'ID client, je dois leur donner cela.

Voici donc le bug. Lorsque je suis arrivé à l'écran Gérer l'API, j'ai vu "Exemple: www.example.com". J'ai tapé l'identifiant du compte de service là-bas, pensant que le format de l'adresse e-mail correspondait mieux à "www.example.com" que l'identifiant du client. J'ai appuyé sur "Autoriser", et l'entrée avait clairement été acceptée et tout était bon. Le résultat ressemble à ceci:

Incorrectly configured screenshot

Il a même généré l'ID client de l'ID de service! Génial! Sauf que mon code obtient une erreur 401 chaque fois que j'essaie de me connecter avec setServiceUser().

Si je retourne à la console Gérer l'accès au client API et si je supprime l'entrée précédente et que j'effectue les mêmes actions, à l'exception de l'ID du client au lieu de l'ID du service. Le résultat est le suivant:

Visible identical screenshot, but correctly configured

Exactement la même chose, mais maintenant je ne suis pas une erreur 401. Il n'y a donc AUCUN moyen de regarder la console et de savoir si vous l'avez configuré avec succès ou non. J'ai testé ce 3 fois pour m'assurer que je ne perdais pas l'esprit ...

+0

Salut Alistair, Excellentes nouvelles! Bien repéré. Je vais essayer par moi-même mais je pense que vous l'avez craqué. –