Accéder à votre domaine Google Apps via un compte de service avec la libraire cliente Ruby

Ruby v2.+


Le but de cet article est d'expliquer synthétiquement comme utiliser un compte de service dans un script Ruby pour accéder aux ressources d'un domaine Google Apps.

Généralités

Tout accès à l'API Google se fait après authentification OAuth2.
Comme expliqué dans la documentation sur le fonctionnement du compte de service avec OAuth2, le consentement de l'utilisateur dont on manipule les données ne sera pas nécessaire : le compte de service, après authentificaton OAuth va agir directement sur l'API.
Cette authentification du compte de service par OAuth2 va nécessiter la création, la signature avec le clé privée et l'échange de jetons (nommés JWT Jason Web Token) entre le script client Ruby utilisant le compte de service et le serveur d'authentification.
La gestion manuelle des jetons (création, encodage base64, signature, url_encodage, expiration, etc) étant assez délicate, Google incite fortement les développeurs à utiliser les librairies clientes qu'il fournit dans les principaux langages pour s'abstraire de cette difficulté.

citations :

Caution: This document is for library developers and platform developers who are comfortable with advanced coding tasks.
The mechanics of server-to-server authentication interactions require applications to create and cryptographically sign JSON Web Tokens (JWTs), and it's easy to make serious errors that can have a severe impact on the security of your application.

Client libraries

When at all possible, do not write the logic for creating and signing JWTs. Instead, we strongly encourage you to use libraries that abstract the cryptography away from your application code. Python, PHP, and Java are currently supported in the Google APIs client libraries, and support across more languages is underway.


Installation de la librairie cliente Ruby

La librairie est proposée sous la forme d'un gem (https://rubygems.org/gems/google-api-client) donc rien de plus simple à installer :
gem install google-api-client

À noter que ce gem installera, si ne vous les avez pas déjà, les gems d'authentification OAuth2, ainsi que le gem Signet qui gére tout le mécanisme d'échange des tokens et de l'authentification.


Accès à Google Apps

Il suffit ensuite simplement de coder l'accès à votre domaine à partir du compte de service.
La documentation de Google sur la librairie cliente Ruby omet de préciser que l'accès doit impérativement associer un compte administrateur du domaine (sans que ce dernier ne donne son mot de passe) au compte de service. Ce mécanisme est nommé impersonation (usurpation d'identité): les accès au domaine sont faits avec le compte de service, mais sous le nom de l'administrateur associé.

Un accès à l'API avec un compte de service nécessite donc :

  • le mail du compte de service
  • un compte administrateur du domaine sous le nom duquel se feront les opérations
  • le fichier de clé privée P12
  • un scope d'API autorisé dans Google Apps

Voici un exemple de code inspiré de https://gist.github.com/thomaswitt/7468182

require 'google/api_client'

# email du compte de service OAuth2 de l'API
SERVICE_ACCOUNT_EMAIL = "b84si5jsf4ndtqnt3@developer.gserviceaccount.com"

# email d'un administrateur du domaine
ACT_ON_BEHALF_EMAIL = "admin@mondomaine.fr"

# chemin du fichier de clé privée du compte de service
PKCS12_FILE = "clientKey.p12"

# Partie de l'API Google interrogée
SCOPE = 'https://www.googleapis.com/auth/admin.directory.user'

# instanciation du client
key = Google::APIClient::KeyUtils.load_from_pkcs12(PKCS12_FILE, 'notasecret')

client = Google::APIClient.new(:application_name => "creation_mails_etudiants", :version => "v0.0.1")

# authentification proprement dite
client.authorization = Signet::OAuth2::Client.new(
  :token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
  :audience => 'https://accounts.google.com/o/oauth2/token',
  :scope => SCOPE,
  :issuer => SERVICE_ACCOUNT_EMAIL,
  :person => ACT_ON_BEHALF_EMAIL,
        # :person = paramètre contenant le nom d'un administrateur pour l'impersonation !
  :signing_key => key)

client.authorization.fetch_access_token!

# récupération des méthodes publiées par l'API
api = client.discovered_api("admin", "directory_v1")

# execution d'une méthode, ici : api.users.get avec une valeur du paramètre userKey
result = client.execute(
  :api_method => api.users.get,
  :parameters => {'userKey' => 'gerard.manvussat@mondomaine.fr'}
  )

# affichage des résultats
users = JSON.parse(result.body, {:symbolize_names => true})
users.each do |u|
  puts "#{u} "
  end

extrait du wiki github source de la libraire :

Service accounts are also used for delegation in Google Apps domains. The target user for impersonation is specified by setting the :person parameter to the user's email address in the credentials

Comments