创建身份连接器

默认情况下,Google Cloud Search 仅识别存储在 Google Cloud Directory(用户和群组)中的 Google 身份。身份连接器用于 将您的企业身份与 Google Cloud Search 使用的 Google 身份同步。

Google 提供了以下选项来开发身份连接器:

  • 身份连接器 SDK。此选项适用于 使用 Java 编程语言。身份连接器 SDK 是 REST API 的封装容器,方便您快速创建连接器。要使用此 SDK 创建身份连接器,请参阅使用身份连接器 SDK 创建身份连接器

  • 低层级 REST API 和 API 库。这些选项适用于不使用 Java 编程或者其代码库更适合 REST API 或 API 库的开发人员。如需使用 REST API 创建身份连接器,请参阅 更改为 Directory API:用户账号: 关于映射用户和 Cloud Identity 文档,适用于 有关映射组的信息。

使用身份连接器 SDK 创建身份连接器

通常,身份连接器可执行以下任务:

  1. 配置连接器。
  2. 从您的企业身份系统中检索所有用户,并将相关信息发送给 Google 以与 Google 身份同步。
  3. 从您的企业身份系统中检索所有群组,并将相关信息发送给 Google 以与 Google 身份同步。

设置依赖项

您必须在构建文件中加入特定的依赖项才能使用 SDK。请点击下面的标签查看构建环境的依赖项:

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'

创建连接器配置

每个连接器都有一个配置文件,其中包含连接器使用的参数,例如代码库的 ID。参数定义为 键值对,例如 api.sourceId=1234567890abcdef

Google Cloud Search SDK 包含 Google 提供的若干个配置参数,可供所有连接器使用。您必须在配置文件中声明以下由 Google 提供的参数:

  • 对于内容连接器,您必须声明 api.sourceIdapi.serviceAccountPrivateKeyFile,因为这些参数用于标识营业地点 和访问代码库所需的私钥。
  • 对于身份连接器,您必须按如下方式声明 api.identitySourceId: 参数用于标识外部身份源的位置。如果您 同步用户,您还必须声明 api.customerId 作为 贵企业的 Google Workspace 账号。

除非您想要覆盖其他由 Google 提供的 参数,则无需在配置文件中声明它们。 有关 Google 提供的配置参数的其他信息, 有关如何生成特定 ID 和密钥的信息,请参阅 Google 提供的配置参数

此外,您还可以定义代码库的专属参数,以便在配置文件中使用。

将配置文件传递给连接器

设置系统属性 config 以将配置文件传递给 连接器。您可以在启动时使用 -D 参数设置该属性 连接。例如,以下命令会启动连接器 替换为 MyConfig.properties 配置文件:

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

如果缺少此参数,SDK 会尝试访问默认配置 文件名为 connector-config.properties 的文件。

使用模板类创建完全同步的身份连接器

身份连接器 SDK 包含一个 FullSyncIdentityConnector 模板类 您可以使用 与 Google 身份相关联本部分将介绍如何使用 FullSyncIdentityConnector 模板,用于通过非 Google 身份对用户和群组执行完全同步 存储库

本文档的这一部分引用了 IdentityConnecorSample.java 示例。此示例从两个 CSV 文件中读取用户和群组身份,并将其与 Google 身份同步。

实现连接器的入口点

连接器的入口点是 main() 方法结合使用。此方法的主要任务是创建一个 Application 类并调用其 start() 方法来运行连接器。

通话前 application.start(), 使用 IdentityApplication.Builder 类来实例化 FullSyncIdentityConnector 模板。FullSyncIdentityConnector 接受 Repository 对象。 以下代码段展示了如何实现 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();
}

SDK 会在后台调用 initConfig() 方法(在连接器的 main() 方法调用之后) Application.buildinitConfig() 方法执行以下任务:

  1. 调用 Configuation.isInitialized() 方法确保 Configuration 尚未初始化。
  2. 使用 Google 提供的键值对初始化 Configuration 对象 对。每个键值对都存储在 ConfigValue 包含在 Configuration 对象中。

实现 Repository 接口

Repository 对象的唯一目的是执行 将代码库身份与 Google 身份同步。使用 您只需要替换 Repository 接口来创建身份连接器。对于 FullTraversalConnector ,那么您可能需要替换以下方法:

  • 通过 init() 方法。要设置和初始化身份代码库,请覆盖 init() 方法。

  • 通过 listUsers() 方法。如需将身份代码库中的所有用户与 Google 用户同步,请替换 listUsers() 方法。

  • 通过 listGroups() 方法。如需将身份代码库中的所有群组与 Google 群组同步,请执行以下操作: 替换 listGroups() 方法。

  • (可选) close() 方法。如果需要清理代码库,请替换 close() 方法。连接器关闭期间会调用一次此方法。

获取自定义配置参数

作为处理连接器配置的一个环节,您需要获取 来自 Configuration 对象。此任务通常在 Repository 类的 init() 方法。

Configuration 类有几种方法可用于获取不同的数据类型 。每个方法都会返回一个 ConfigValue 对象。然后,您将使用 ConfigValue 对象的 get() 方法检索实际值。 以下代码段展示了如何检索 userMappingCsvPathConfiguration 对象中的 groupMappingCsvPath 值:

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();
}

要获取和解析包含多个值的参数,请使用 Configuration 类的类型解析器将数据解析为离散区块。 在示例教程中,我们会看到连接器中的以下代码段使用 getMultiValue 方法来获取 GitHub 代码库名称列表:

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

获取所有用户的映射

替换 listUsers() 从身份代码库中检索所有用户的映射。通过 listUsers() 方法接受表示要获取的最后一个身份的检查点 已同步。因此即使进程被中断,也可以利用该检查点以恢复同步。对于代码库中的每个用户,您将在 listUsers() 方法:

  1. 获取包含 Google 身份和相关外部身份的映射。
  2. 将该键值对打包到 listUsers() 方法返回的迭代器中。

获取用户映射

以下代码段演示了如何检索存储在 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);
    }
  }
  // ...
}

将用户映射打包到迭代器中

listUsers() 方法会返回一个 Iterator,具体来说, CheckpointCloseableIterable, / IdentityUser 对象的操作。您可以使用 CheckpointClosableIterableImpl.Builder 类来构建和返回迭代器。以下代码段显示了如何将每个映射打包到列表中,然后从该列表构建迭代器:

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

获取群组

替换 listGroups() 从您的身份中检索所有群组及其成员 存储库listGroups() 方法接受表示最后一个 要同步的身份。因此即使进程被中断,也可以利用该检查点以恢复同步。对于代码库中的每个用户,您将执行以下操作: listGroups() 方法中的步骤进行操作:

  1. 获取群组及其成员。
  2. 将每个群组及其成员打包到 listGroups() 方法结合使用。

获取群组身份

以下代码段演示了如何检索存储在 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);
    }
  }
  // ...

}

将群组和成员打包到迭代器中

listGroups() 方法会返回一个 Iterator,具体来说, CheckpointCloseableIterable, / IdentityGroup 对象的操作。 您可以使用 CheckpointClosableIterableImpl.Builder 类来构建和返回迭代器。以下代码段展示了如何 将每个群组及其成员打包到一个列表中,并根据该列表构建迭代器 列表:

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

后续步骤

您可以执行以下几个后续步骤:

  • (可选)实现 close() 方法以在运行结束前释放所有资源。
  • (可选)使用内容连接器 SDK 创建内容连接器