ID 커넥터 만들기

기본적으로 Google Cloud Search는 Google Cloud 디렉터리의 Google ID만 인식합니다. ID 커넥터를 사용하여 기업 ID를 Cloud Search에서 사용하는 Google ID와 동기화합니다.

Google에서는 다음과 같은 ID 커넥터 개발 옵션을 제공합니다.

  • ID 커넥터 SDK: Java 프로그래머에게 가장 적합합니다. SDK는 커넥터를 빠르게 만들 수 있는 REST API를 둘러싸는 래퍼입니다. SDK를 사용하려면 ID 커넥터 SDK를 사용하여 ID 커넥터 만들기를 참고하세요.

  • 하위 수준 REST API 및 API 라이브러리: Java 프로그래머가 아닌 사용자에게 가장 적합합니다. REST API를 사용하여 ID 커넥터를 만들려면 사용자 매핑은 Directory API: 사용자 계정을 참고하고 그룹 매핑은 Google Cloud ID 문서를 참고하세요.

ID 커넥터 SDK를 사용하여 ID 커넥터 만들기

일반적인 ID 커넥터는 다음 작업을 수행합니다.

  1. 커넥터를 구성합니다.
  2. ID 시스템에서 사용자를 가져와 Google로 전송합니다.
  3. ID 시스템에서 그룹을 가져와 Google로 보냅니다.

종속 항목 설정

빌드 파일에 이러한 종속 항목을 포함합니다.

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 제공 매개변수가 포함되어 있습니다. 구성 파일에서 다음을 선언해야 합니다.

  • 콘텐츠 커넥터: api.sourceIdapi.serviceAccountPrivateKeyFile을 선언합니다. 이러한 매개변수는 저장소와 액세스에 필요한 비공개 키를 식별합니다.
  • ID 커넥터: api.identitySourceId를 선언하여 외부 ID 소스를 식별합니다. 사용자 동기화의 경우 api.customerId (Google Workspace 계정의 고유 ID)도 선언합니다.

다른 Google 제공 매개변수는 기본값을 재정의하는 경우에만 선언합니다. ID 및 키 생성에 관한 자세한 내용은 Google 제공 매개변수를 참고하세요.

구성 파일에서 저장소별 매개변수를 정의할 수도 있습니다.

커넥터에 구성 파일 전달

config 시스템 속성을 설정하여 구성 파일을 전달합니다. 커넥터를 시작할 때 -D 인수를 사용합니다. 예를 들면 다음과 같습니다.

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

이 인수를 생략하면 SDK는 로컬 디렉터리에서 connector-config.properties라는 파일을 사용하려고 시도합니다.

템플릿 클래스를 사용하여 전체 동기화 ID 커넥터 만들기

SDK에는 저장소의 모든 사용자 및 그룹을 동기화하는 FullSyncIdentityConnector 템플릿이 포함되어 있습니다. 이 섹션에서는 사용 방법을 설명합니다.

이 섹션에서는 CSV 파일에서 ID를 읽는 IdentityConnectorSample.java 샘플의 코드를 참조합니다.

커넥터 진입점 구현

진입점은 main() 메서드입니다. Application 인스턴스를 만들고 start()을 호출하여 커넥터를 실행합니다.

application.start()를 호출하기 전에 IdentityApplication.Builder를 사용하여 FullSyncIdentityConnector 템플릿을 인스턴스화합니다.

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는 main() 메서드가 Application.build()를 호출한 후 initConfig()를 호출합니다. initConfig() 메서드:

  1. Configuration이 이미 초기화되지 않았는지 확인합니다.
  2. Google에서 제공하는 키-값 쌍으로 Configuration 객체를 초기화합니다.

저장소 인터페이스 구현

Repository 객체는 저장소 ID를 Google ID에 동기화합니다. 템플릿을 사용하는 경우 특정 메서드만 재정의하면 됩니다. FullSyncIdentityConnector의 경우 다음 메서드를 재정의합니다.

커스텀 구성 매개변수 가져오기

일반적으로 init() 메서드에서 Configuration 객체로부터 맞춤 매개변수를 가져옵니다. 다음 스니펫은 CSV 경로를 가져오는 방법을 보여줍니다.

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()를 재정의하여 사용자 매핑을 가져옵니다. 이 메서드는 중단된 경우 동기화를 재개하기 위한 체크포인트를 허용합니다. 각 사용자에 대해 다음을 수행합니다.

  1. Google ID와 외부 ID 간의 매핑을 가져옵니다.
  2. 이 쌍을 listUsers()에서 반환된 반복자에 패키징합니다.

사용자 매핑 가져오기

이 스니펫은 CSV 파일에서 ID 매핑을 가져오는 방법을 보여줍니다.

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() 메서드는 IdentityUser 객체의 CheckpointCloseableIterable를 반환합니다.

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

그룹 가져오기

listGroups()를 재정의하여 그룹과 구성원을 가져옵니다. 이 메서드는 체크포인트를 받습니다. 각 그룹에 대해 다음을 수행합니다.

  1. 그룹과 구성원을 가져옵니다.
  2. listGroups()에서 반환된 반복자에 패키징합니다.

그룹 ID 가져오기

이 스니펫은 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() 메서드는 IdentityGroup 객체의 CheckpointCloseableIterable를 반환합니다.

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

다음 단계