Criar um conector de identidade

Por padrão, o Google Cloud Search reconhece apenas identidades do Google armazenadas no Google Cloud Directory (usuários e grupos). Os conectores de identidade são usados para sincronizar as identidades da sua empresa com as identidades do Google usadas pelo Google Cloud Search.

O Google oferece as seguintes opções para desenvolver conectores de identidade:

  • O SDK do Identity Connector. Essa opção é destinada a desenvolvedores que estão programando na linguagem Java. O SDK do Identity Connector é um wrapper na API REST que permite criar conectores rapidamente. Para criar um conector de identidade com o SDK, consulte Criar um conector de identidade usando o SDK do Identity Connector.

  • Uma API REST de baixo nível e bibliotecas de API. Estas opções são para desenvolvedores que podem não estar programando em Java ou têm uma base de código que comporta melhor uma API REST ou uma biblioteca. Para criar um conector de identidade usando a API REST, consulte API Directory: contas de usuários para ver informações sobre como mapear usuários e a documentação do Cloud Identity para informações sobre mapeamento de grupos.

Criar um conector de identidade usando o SDK do Identity Connector

Um conector de identidade típico desempenha as seguintes tarefas:

  1. Configura o conector.
  2. Recupera todos os usuários do sistema de identidade empresarial e os envia ao Google para sincronização com as identidades do Google.
  3. Recupera todos os grupos do sistema de identidade empresarial e os envia ao Google para sincronização com as identidades do Google.

Configurar dependências

Você precisa incluir determinadas dependências no seu arquivo de compilação para usar o SDK. Clique em uma guia abaixo para ver as dependências do ambiente de compilação:

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'

Criar a configuração do conector

Cada conector tem um arquivo de configuração que contém os parâmetros usados pelo conector, como o código do repositório. Os parâmetros são definidos como pares de chave-valor, como api.sourceId=1234567890abcdef.

O SDK do Google Cloud Search contém vários parâmetros de configuração fornecidos pelo Google que são usados por todos os conectores. É necessário declarar os parâmetros fornecidos pelo Google a seguir no arquivo de configuração:

  • Para um conector de conteúdo, é necessário declarar api.sourceId e api.serviceAccountPrivateKeyFile, porque esses parâmetros identificam o local do repositório e a chave privada necessários para acessá-lo.
  • Para um conector de identidade, declare api.identitySourceId, porque esse parâmetro identifica o local da sua origem de identidade externa. Se você estiver sincronizando usuários, também será necessário declarar api.customerId como o ID exclusivo da conta do Google Workspace da sua empresa.

A menos que você queira modificar os valores padrão dos outros parâmetros fornecidos pelo Google, não é necessário declará-los no arquivo de configuração. Para ver mais informações sobre os parâmetros de configuração fornecidos pelo Google, por exemplo, como gerar determinados IDs e chaves, consulte Parâmetros de configuração fornecidos pelo Google.

Também é possível definir parâmetros específicos do repositório para usá-los no seu arquivo de configuração.

Transmitir o arquivo de configuração para o conector

Defina a propriedade do sistema config para transmitir o arquivo de configuração para o conector. Você pode definir a propriedade usando o argumento -D ao iniciar o conector. Por exemplo, o comando a seguir inicia o conector com o arquivo de configuração MyConfig.properties:

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

Se esse argumento estiver ausente, o SDK tentará acessar um arquivo de configuração padrão chamado connector-config.properties.

Criar um conector de identidade de sincronização completo usando uma classe de modelo

O SDK do Identity Connector contém uma classe de modelo FullSyncIdentityConnector que pode ser usada para sincronizar todos os usuários e grupos do repositório de identidades com as identidades do Google. Nesta seção, explicamos como usar o modelo FullSyncIdentityConnector para realizar uma sincronização completa de usuários e grupos em um repositório de identidades que não seja do Google.

Nesta seção da documentação, são usados snippets de código da amostra IdentityConnecorSample.java. Essa amostra lê as identidades de usuários e grupos de dois arquivos CSV e as sincroniza com as identidades do Google.

Implementar o ponto de entrada do conector

O ponto de entrada para um conector é o método main(). A tarefa principal desse método é criar uma instância da classe Application e invocar o método start() para executar o conector.

Antes de chamar application.start(), use a classe IdentityApplication.Builder para instanciar o modelo FullSyncIdentityConnector. O FullSyncIdentityConnector aceita um objeto Repository com métodos que você implementará. O snippet de código a seguir mostra como implementar o método 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();
}

Em segundo plano, o SDK chama o método initConfig() depois que o método main() do conector chama Application.build. O método initConfig() executa as seguintes tarefas:

  1. Chama o método Configuation.isInitialized() para garantir que o Configuration não tenha sido inicializado.
  2. Inicializa um objeto Configuration com os pares de chave-valor fornecidos pelo Google. Cada par de chave-valor é armazenado em um objeto ConfigValue no objeto Configuration.

Implementar a interface Repository

O único objetivo do objeto Repository é executar a sincronização de identidades de repositório com as identidades do Google. Ao usar um modelo, você precisa modificar apenas determinados métodos na interface Repository para criar um conector de identidade. Para o FullTraversalConnector, provavelmente você vai substituir os seguintes métodos:

  • O método init(). Para executar qualquer configuração e inicialização do repositório de identidades, modifique o método init().

  • O método listUsers(). Para sincronizar todos os usuários no repositório de identidades com os usuários do Google, modifique o método listUsers().

  • O método listGroups(). Para sincronizar todos os grupos no repositório de identidades com os grupos do Google, substitua o método listGroups().

  • (opcional) O método close(). Se você precisar realizar a limpeza do repositório, modifique o método close(). Esse método é chamado uma vez durante o encerramento do conector.

Receber parâmetros de configuração personalizados

Como parte da configuração do conector, é necessário receber todos os parâmetros personalizados do objeto Configuration. Essa tarefa geralmente é realizada em um método init() da classe Repository.

A classe Configuration tem vários métodos para receber tipos de dados diferentes de uma configuração. Cada método retorna um objeto ConfigValue. Em seguida, você usará o método get() do objeto ConfigValue para recuperar o valor real. O snippet a seguir mostra como recuperar o valor userMappingCsvPath e groupMappingCsvPath de um objeto 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();
}

Para acessar e analisar um parâmetro que contém vários valores, use um dos analisadores de tipo de classe Configuration para analisar os dados em blocos discretos. O snippet a seguir, do conector do tutorial, usa o método getMultiValue para ver uma lista de nomes de repositório do GitHub:

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

Receber o mapeamento de todos os usuários

Modifique listUsers() para recuperar o mapeamento de todos os usuários no repositório de identidades. O método listUsers() aceita um checkpoint que representa a última identidade a ser sincronizada. O checkpoint poderá ser usado para retomar a sincronização caso o processo seja interrompido. Para cada usuário no repositório, execute estas etapas no método listUsers():

  1. Receba um mapeamento que consiste na identidade do Google e na identidade externa associada.
  2. Agrupe o par em um iterador retornado pelo método listUsers().

Receber um mapeamento de usuários

Veja no snippet de código a seguir como recuperar os mapeamentos de identidade armazenados em um arquivo 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);
    }
  }
  // ...
}

Empacotar um mapeamento de usuários em um iterador

O método listUsers() retorna um Iterator, especificamente um CheckpointCloseableIterable, de objetos IdentityUser. Você pode usar a classe CheckpointClosableIterableImpl.Builder para construir e retornar um iterador. Veja no snippet de código a seguir como empacotar cada mapeamento na lista e criar o iterador a partir dela:

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

Receber um grupo

Modifique listGroups() para recuperar todos os grupos e os participantes do repositório de identidades. O método listGroups() aceita um checkpoint que representa a última identidade a ser sincronizada. O checkpoint poderá ser usado para retomar a sincronização caso o processo seja interrompido. Para cada usuário no repositório, realize estas etapas no método listGroups():

  1. Obter o grupo e os membros dele.
  2. Agrupe cada grupo e membros em um iterador retornado pelo método listGroups().

Receber a identidade do grupo

Veja no snippet de código abaixo como recuperar os grupos e seus membros armazenados em um arquivo 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);
    }
  }
  // ...

}

Empacotar o grupo e respectivos membros em um iterador

O método listGroups() retorna um Iterator, especificamente um CheckpointCloseableIterable, de objetos IdentityGroup. Você pode usar a classe CheckpointClosableIterableImpl.Builder para construir e retornar um iterador. Veja no snippet de código a seguir como empacotar cada grupo e seus membros em uma lista e criar o iterador a partir dela:

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

A seguir

Veja a seguir algumas das próximas etapas: