Erreur lors de la création d'un événement d'agenda Google avec un compte de service

Dec 19 2020

J'ai l'obligation de créer un événement de calendrier Google sur un calendrier et d'ajouter d'autres utilisateurs en tant que participants à cet événement. L'objectif est d'envoyer des événements d'agenda aux utilisateurs de l'application sans prendre leur consentement (O-Auth).

Après avoir lu la documentation de Google, j'ai découvert que j'avais besoin d'un compte de service. J'ai donc créé un projet et un compte de service à partir de l'une des adresses e-mail de notre G-Suite, [email protected] et activé l'API de calendrier pour le même.

J'ai créé et téléchargé une paire de clés (JSON) dont le contenu est,

{
  "type": "service_account",
  "project_id": "*****",
  "private_key_id": "bdbbcd**************49f77d599f2",
  "private_key": "**"
  "client_email": "******@*****.iam.gserviceaccount.com",
  "client_id": "11083******576856",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/****dev%40*****kdev.iam.gserviceaccount.com"
}

Et selon la documentation, j'ai procédé à l'écriture du code de flux d'authentification,

public static GoogleCredential doOauth( String credsPath ) throws IOException
    {
        GoogleCredential credential = GoogleCredential.fromStream(new FileInputStream(credsPath))
                .createScoped(Collections.singleton(CalendarScopes.CALENDAR));
        System.out.println(credential);
        return credential;
    }

L' credentialobjet contient la plupart des détails du fichier de clé. Mais, les champs, serviceAccountUser, accessToken, refreshToken, clientAuthenticationet requestInitializeront nullvaleur. (Je suppose que quelque chose ne va pas ici)

Maintenant, en utilisant le credentialObject, j'ai continué à écrire le code selon la documentation pour créer l'événement.

GoogleCredential credential = doOauth(CREDENTIALS_FILE_PATH);
        Event event = new Event().setSummary("Google I/O 2015").setLocation("800 Howard St., San Francisco, CA 94103")
                .setDescription("A chance to hear more about Google's developer products.");
        final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();

        DateTime startDateTime = new DateTime("2020-12-28T09:00:00-07:00");
        EventDateTime start = new EventDateTime().setDateTime(startDateTime).setTimeZone("America/Los_Angeles");
        event.setStart(start);

        DateTime endDateTime = new DateTime("2020-12-28T17:00:00-07:00");
        EventDateTime end = new EventDateTime().setDateTime(endDateTime).setTimeZone("America/Los_Angeles");
        event.setEnd(end);

        String[] recurrence = new String[] { "RRULE:FREQ=DAILY;COUNT=2" };
        event.setRecurrence(Arrays.asList(recurrence));

        EventAttendee[] attendees = new EventAttendee[] { new EventAttendee().setEmail("[email protected]") };
        event.setAttendees(Arrays.asList(attendees));

        EventReminder[] reminderOverrides = new EventReminder[] {
                new EventReminder().setMethod("email").setMinutes(24 * 60),
                new EventReminder().setMethod("popup").setMinutes(10), };
        Event.Reminders reminders = new Event.Reminders().setUseDefault(false)
                .setOverrides(Arrays.asList(reminderOverrides));
        event.setReminders(reminders);
        String calendarId = "primary";
        Calendar service = new Calendar.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential)
                .setApplicationName("testapp").build();
        event = service.events().insert(calendarId, event).execute();
        System.out.printf("Event created: %s\n", event.getHtmlLink());

Mais, cela a abouti à l'erreur,

{
  "code" : 403,
  "errors" : [ {
    "domain" : "calendar",
    "message" : "Service accounts cannot invite attendees without Domain-Wide Delegation of Authority.",
    "reason" : "forbiddenForServiceAccounts"
  } ],
  "message" : "Service accounts cannot invite attendees without Domain-Wide Delegation of Authority."
}

Après avoir passé du temps Domain-Wide Delegation, j'ai compris que cela est nécessaire si nous devons envoyer l'événement en tant qu'autre utilisateur depuis notre g-suite, ce qui n'est pas nécessaire pour mon problème. Mais, pour déboguer, j'ai continué et fourni Domain-Wide Delegationet relancé le programme. La même erreur est revenue.

J'ai donc supprimé les invités / participants de l' eventobjet et relancé l'application. Cette fois, le programme s'est exécuté sans aucune erreur, mais le lien d'événement généré, au clic, indique Could not find the requested event.

Je ne vois aucun exemple d'utilisation du compte de service via les bibliothèques clientes java sur le lien développeur google.

Pouvez-vous s'il vous plaît me faire savoir ce qui ne va pas ici et la documentation officielle / de travail sur la façon exacte de créer un événement de calendrier google à partir de mon projet ajouter d'autres utilisateurs (non g suite également) à ajouter en tant que participants, de sorte que je n'ai pas obtenir le consentement d'autres utilisateurs pour ajouter des événements à leur propre calendrier?

Merci.

Réponses

DaImTo Dec 21 2020 at 15:06

Tout d'abord, je tiens à dire que c'est quelque chose de nouveau, si vous voyez beaucoup de questions et des didacticiels qui n'indiquaient pas que vous deviez le faire, c'est parce que les comptes de service pouvaient envoyer des invitations, c'est quelque chose de verrouillé par Google. Il ya environ un an.

Cela devrait fonctionner mais je ne l'ai pas testé car je n'ai plus accès à un compte Gsuite. L'administrateur gsuite doit configurer la délégation à l' échelle du domaine à un autre utilisateur. Ensuite, le compte de service doit emprunter l'identité de cet utilisateur pour qu'il apparaisse comme cet utilisateur est celui qui envoie les invitations.

Le seul exemple que j'ai de la façon dont cela est ajouté est dans .net

Exemple de .net

var gsuiteUser = "[email protected]";
var serviceAccountCredentialInitializer = new ServiceAccountCredential.Initializer(serviceAccount)
            {
                User = gsuiteUser,
                Scopes = new[] { GmailService.Scope.GmailSend, GmailService.Scope.GmailLabels }

            }.FromCertificate(certificate);

Exemple de devinette Java

Je ne suis pas un développeur Java, mais la bibliothèque cliente .net et la bibliothèque cliente Java sont très proches dans la façon dont elles ont été développées. Je suppose que vous recherchez une méthode appelée setServiceAccountUser

GoogleCredential credential = new  GoogleCredential.Builder().setTransport(HTTP_TRANSPORT)
                .setJsonFactory(JSON_FACTORY)
                .setServiceAccountId(SERVICE_ACCOUNT_EMAIL)
                .setServiceAccountScopes(CalendarScopes.CALENDAR)
                .setServiceAccountPrivateKeyFromP12File(credsPath))
                .setServiceAccountUser(gsuiteUser)
                .build();
  • OAuth2 pour les comptes de service