Créer un connecteur d'identité

Par défaut, Google Cloud Search ne reconnaît que les identités Google stockées dans Google Cloud Directory (utilisateurs et groupes). Les connecteurs d'identité permettent de synchroniser les identités de votre entreprise avec les identités Google utilisées par Google Cloud Search.

Google propose les options suivantes pour développer des connecteurs d'identité:

  • Le SDK Identity Connector. Cette option est destinée aux développeurs qui programment en langage Java. Le SDK Identity Connector est un wrapper pour l'API REST qui accélère la création des connecteurs. Pour créer un connecteur d'identité à l'aide du SDK, consultez la section Créer un connecteur d'identité à l'aide du SDK Identity Connector.

  • Une API REST de bas niveau et des bibliothèques d'API. Ces options sont destinées aux développeurs qui ne programment pas en Java, ou dont la base de code est mieux adaptée à une API REST ou à une bibliothèque. Pour créer un connecteur d'identité à l'aide de l'API REST, consultez la page API Directory: comptes utilisateur pour en savoir plus sur le mappage des utilisateurs, et la documentation de Cloud Identity pour en savoir plus sur le mappage des groupes.

Créer un connecteur d'identité à l'aide du SDK Identity Connector

Un connecteur d'identité standard effectue les tâches suivantes:

  1. Configurez le connecteur.
  2. Récupération de tous les utilisateurs du système d'identité de votre entreprise et envoi de ceux-ci à Google pour synchronisation avec les identités Google
  3. Récupération de tous les groupes du système d'identité de votre entreprise et envoi de ceux-ci à Google pour synchronisation avec les identités Google

Configurer des dépendances

Pour utiliser le SDK, vous devez ajouter des dépendances dans le fichier de compilation. Cliquez sur un onglet ci-dessous afin d'afficher les dépendances pour votre environnement de compilation:

Maven

<dependency>
<groupId>com.google.enterprise.cloudsearch</groupId>
<artifactId>google-cloudsearch-identity-connector-sdk</artifactId>
<version>v1-0.0.3</version>
</dependency>

Gradle

 compile group: 'com.google.enterprise.cloudsearch',
         name: 'google-cloudsearch-identity-connector-sdk',
         version: 'v1-0.0.3'

Créer votre configuration de connecteur

Chaque connecteur dispose d'un fichier de configuration contenant ses paramètres (comme l'ID de votre dépôt), Les paramètres sont définis sous forme de paires clé-valeur, par exemple api.sourceId=1234567890abcdef.

Le SDK Google Cloud Search contient plusieurs paramètres de configuration fournis par Google qui sont utilisés par tous les connecteurs. Les paramètres suivants (fournis par Google) sont à déclarer dans votre fichier de configuration:

  • Pour un connecteur de contenu, vous devez déclarer api.sourceId et api.serviceAccountPrivateKeyFile, car ces paramètres identifient l'emplacement de votre dépôt et du fichier contenant la clé privée nécessaire pour y accéder.
  • Pour un connecteur d'identité, vous devez déclarer api.identitySourceId, car ce paramètre identifie l'emplacement de la source d'identité externe. En cas de synchronisation des utilisateurs, déclarez également api.customerId comme ID unique pour le compte Google Workspace de votre entreprise.

À moins que vous souhaitiez remplacer les valeurs par défaut d'autres paramètres fournis par Google, il est inutile de déclarer ces paramètres dans votre fichier de configuration. Pour plus d'informations sur les paramètres de configuration fournis par Google, concernant la génération de certains ID et de certaines clés, entre autres, reportez-vous à la page Paramètres de configuration fournis par Google.

Vous pouvez également définir des paramètres personnalisés propres au dépôt dans votre fichier de configuration.

Transmettre le fichier de configuration au connecteur

Définissez la propriété système config de manière à transmettre le fichier de configuration à votre connecteur. Pour ce faire, utilisez l'argument -D lors du démarrage du connecteur. Par exemple, la commande suivante permet de démarrer le connecteur avec le fichier de configuration MyConfig.properties:

java -classpath myconnector.jar;... -Dconfig=MyConfig.properties MyConnector

Si cet argument n'est pas transmis, le SDK tente d'accéder à un fichier de configuration par défaut nommé connector-config.properties.

Créer un connecteur d'identité pour la synchronisation complète à l'aide d'un modèle de classe

Le SDK Identity Connector comprend un modèle de classe FullSyncIdentityConnector qui vous permet de synchroniser tous les utilisateurs et groupes de votre dépôt d'identités avec les identités Google. Cette section explique comment effectuer une synchronisation complète des utilisateurs et des groupes à partir d'un dépôt d'identités non-Google à l'aide du modèle FullSyncIdentityConnector.

Cette section fait référence aux extraits de code de l'exemple IdentityConnecorSample.java. Cet exemple lit les identités des utilisateurs et des groupes à partir de deux fichiers CSV, puis les synchronise avec les identités Google.

Implémenter le point d'entrée du connecteur

Le point d'entrée d'un connecteur est la méthode main(). La fonction principale de cette méthode consiste à créer une instance de la classe Application et à appeler sa méthode start() pour exécuter le connecteur.

Avant d'appeler application.start(), utilisez la classe IdentityApplication.Builder pour instancier le modèle FullSyncIdentityConnector. Le modèle FullSyncIdentityConnector accepte un objet Repository dont vous utiliserez les méthodes. L'extrait de code suivant montre comment mettre en œuvre la méthode main():

IdentityConnectorSample.java
/**
 * This sample connector uses the Cloud Search SDK template class for a full
 * sync connector. In the full sync case, the repository is responsible
 * for providing a snapshot of the complete identity mappings and
 * group rosters. This is then reconciled against the current set
 * of mappings and groups in Cloud Directory.
 *
 * @param args program command line arguments
 * @throws InterruptedException thrown if an abort is issued during initialization
 */
public static void main(String[] args) throws InterruptedException {
  Repository repository = new CsvRepository();
  IdentityConnector connector = new FullSyncIdentityConnector(repository);
  IdentityApplication application = new IdentityApplication.Builder(connector, args).build();
  application.start();
}

En arrière-plan, le SDK appelle la méthode initConfig(), après que la méthode main() de votre connecteur a appelé Application.build. La méthode initConfig() effectue les tâches suivantes:

  1. appelle la méthode Configuation.isInitialized() pour confirmer que l'objet Configuration n'a pas été initialisé ;
  2. Initialise un objet Configuration avec les paires clé-valeur fournies par Google. Chaque paire clé-valeur est stockée dans un objet ConfigValue au sein de l'objet Configuration.

Implémenter l'interface Repository

L'objet Repository a pour unique objectif de synchroniser les identités du dépôt avec celles de Google. Lorsque vous utilisez un modèle, il vous suffit de remplacer certaines méthodes dans l'interface Repository pour créer un connecteur d'identité. Pour le modèle FullTraversalConnector, vous devrez probablement remplacer les méthodes suivantes:

  • La méthode init(). Pour configurer et initialiser un dépôt d'identités, remplacez la méthode init().

  • La méthode listUsers(). Pour synchroniser tous les utilisateurs du dépôt d'identités avec les utilisateurs Google, remplacez la méthode listUsers().

  • La méthode listGroups(). Pour synchroniser tous les groupes du dépôt d'identités avec Google Groups, remplacez la méthode listGroups().

  • (Facultatif) La méthode close(). Si vous devez procéder au nettoyage du dépôt, remplacez la méthode close(). Cette méthode est appelée une fois lors de l'arrêt du connecteur.

Obtenir les paramètres de configuration personnalisés

Lorsque vous effectuez la configuration de votre connecteur, vous devez récupérer les éventuels paramètres personnalisés contenus dans l'objet Configuration. Cette tâche est généralement effectuée dans une méthode init() de la classe Repository.

La classe Configuration comprend plusieurs méthodes qui permettent d'obtenir différents types de données à partir d'une configuration. Chaque méthode renvoie un objet ConfigValue. Pour récupérer la valeur réelle, utilisez ensuite la méthode get() de l'objet ConfigValue. L'extrait de code suivant montre comment extraire les valeurs userMappingCsvPath et groupMappingCsvPath à partir d'un objet Configuration:

IdentityConnectorSample.java
/**
 * Initializes the repository once the SDK is initialized.
 *
 * @param context Injected context, contains convenienve methods
 *                for building users & groups
 * @throws IOException if unable to initialize.
 */
@Override
public void init(RepositoryContext context) throws IOException {
  log.info("Initializing repository");
  this.context = context;
  userMappingCsvPath = Configuration.getString(
      "sample.usersFile", "users.csv").get().trim();
  groupMappingCsvPath = Configuration.getString(
      "sample.groupsFile", "groups.csv").get().trim();
}

Pour récupérer et analyser un paramètre contenant plusieurs valeurs, utilisez l'un des analyseurs de type de la classe Configuration, qui permettent d'analyser les données par fragments distincts. L'extrait de code suivant (issu du connecteur du tutoriel) permet d'obtenir la liste des noms de dépôts GitHub grâce à la méthode getMultiValue:

GithubRepository.java
ConfigValue<List<String>> repos = Configuration.getMultiValue(
    "github.repos",
    Collections.emptyList(),
    Configuration.STRING_PARSER);

Récupérer le mappage de tous les utilisateurs

Remplacez la méthode listUsers() pour récupérer le mappage de tous les utilisateurs à partir de votre dépôt d'identités. La méthode listUsers() accepte un point de contrôle représentant la dernière identité à synchroniser. Le point de contrôle peut servir à reprendre la synchronisation si le processus est interrompu. Pour chaque utilisateur de votre dépôt, vous accomplirez les tâches suivantes dans la méthode listUsers():

  1. Récupérer un mappage comprenant l'identité Google et l'identité externe associée
  2. Empaquetez ces deux éléments dans un itérateur renvoyé par la méthode listUsers().

Obtenir un mappage d'utilisateurs

L'extrait de code suivant montre comment récupérer les mappages d'identités stockés dans un fichier CSV:

IdentityConnectorSample.java
/**
 * Retrieves all user identity mappings for the identity source. For the
 * full sync connector, the repository must provide a complete snapshot
 * of the mappings. This is reconciled against the current mappings
 * in Cloud Directory. All identity mappings returned here are
 * set in Cloud Directory. Any previously mapped users that are omitted
 * are unmapped.
 *
 * The connector does not create new users. All users are assumed to
 * exist in Cloud Directory.
 *
 * @param checkpoint Saved state if paging over large result sets. Not used
 *                   for this sample.
 * @return Iterator of user identity mappings
 * @throws IOException if unable to read user identity mappings
 */
@Override
public CheckpointCloseableIterable<IdentityUser> listUsers(byte[] checkpoint)
    throws IOException {
  List<IdentityUser> users = new ArrayList<>();
  try (Reader in = new FileReader(userMappingCsvPath)) {
    // Read user mappings from CSV file
    CSVParser parser = CSVFormat.RFC4180
        .withIgnoreSurroundingSpaces()
        .withIgnoreEmptyLines()
        .withCommentMarker('#')
        .parse(in);
    for (CSVRecord record : parser.getRecords()) {
      // Each record is in form: "primary_email", "external_id"
      String primaryEmailAddress = record.get(0);
      String externalId = record.get(1);
      if (primaryEmailAddress.isEmpty() || externalId.isEmpty()) {
        // Skip any malformed mappings
        continue;
      }
      log.info(() -> String.format("Adding user %s/%s",
          primaryEmailAddress, externalId));

      // Add the identity mapping
      IdentityUser user = context.buildIdentityUser(
          primaryEmailAddress, externalId);
      users.add(user);
    }
  }
  // ...
}

Empaqueter un mappage d'utilisateurs dans un itérateur

La méthode listUsers() renvoie un Iterator (plus précisément un CheckpointCloseableIterable) d'objets IdentityUser. Vous pouvez construire et renvoyer un itérateur à l'aide de la classe CheckpointClosableIterableImpl.Builder. L'extrait de code suivant montre comment empaqueter chaque mappage dans l'itérateur de création de liste à partir de cette liste:

IdentityConnectorSample.java
CheckpointCloseableIterable<IdentityUser> iterator =
  new CheckpointCloseableIterableImpl.Builder<IdentityUser>(users)
      .setHasMore(false)
      .setCheckpoint((byte[])null)
      .build();

Obtenir un groupe

Remplacez la méthode listGroups() pour récupérer tous les groupes et leurs membres à partir de votre dépôt d'identités. La méthode listGroups() accepte un point de contrôle représentant la dernière identité à synchroniser. Le point de contrôle peut servir à reprendre la synchronisation si le processus doit être interrompu. Pour chaque utilisateur de votre dépôt, vous accomplirez les tâches suivantes dans la méthode listGroups():

  1. Récupérer le groupe et ses membres
  2. Empaqueter chaque groupe et ses membres dans un itérateur renvoyé par la méthode listGroups()

Récupérer l'identité du groupe

L'extrait de code suivant montre comment récupérer les groupes et les membres stockés dans un fichier CSV:

IdentityConnectorSample.java
/**
 * Retrieves all group rosters for the identity source. For the
 * full sync connector, the repository must provide a complete snapshot
 * of the rosters. This is reconciled against the current rosters
 * in Cloud Directory. All groups and members  returned here are
 * set in Cloud Directory. Any previously created groups or members
 * that are omitted are removed.
 *
 * @param checkpoint Saved state if paging over large result sets. Not used
 *                   for this sample.
 * @return Iterator of group rosters
 * @throws IOException if unable to read groups
 */    @Override
public CheckpointCloseableIterable<IdentityGroup> listGroups(byte[] checkpoint)
    throws IOException {
  List<IdentityGroup> groups = new ArrayList<>();
  try (Reader in = new FileReader(groupMappingCsvPath)) {
    // Read group rosters from CSV
    CSVParser parser = CSVFormat.RFC4180
        .withIgnoreSurroundingSpaces()
        .withIgnoreEmptyLines()
        .withCommentMarker('#')
        .parse(in);
    for (CSVRecord record : parser.getRecords()) {
      // Each record is in form: "group_id", "member"[, ..., "memberN"]
      String groupName = record.get(0);
      log.info(() -> String.format("Adding group %s", groupName));
      // Parse the remaining columns as group memberships
      Supplier<Set<Membership>> members = new MembershipsSupplier(record);
      IdentityGroup group = context.buildIdentityGroup(groupName, members);
      groups.add(group);
    }
  }
  // ...

}

Empaqueter le groupe et ses membres dans un itérateur

La méthode listGroups() renvoie un Iterator (plus précisément un CheckpointCloseableIterable) d'objets IdentityGroup. Vous pouvez construire et renvoyer un itérateur à l'aide de la classe CheckpointClosableIterableImpl.Builder. L'extrait de code suivant montre comment empaqueter chaque groupe et ses membres dans l'itérateur de création de liste à partir de cette liste:

IdentityConnectorSample.java
CheckpointCloseableIterable<IdentityGroup> iterator =
   new CheckpointCloseableIterableImpl.Builder<IdentityGroup>(groups)
      .setHasMore(false)
      .setCheckpoint((byte[])null)
      .build();

Étapes suivantes

Voici quelques étapes que vous pouvez également suivre :