はじめに
midPoint by OpenStandia Advent Calendar 2024 の8日目は、5日目に続いてmidPointの設定を行い、今度は組織情報を含むCSV形式の源泉データをmidPointにインポートします。
5日目で構築した環境が前提となります。
源泉データの準備
サンプルの組織情報を含む源泉データを準備します。なお、このダミーの組織情報もChatGPTに生成してもらいました。parentOrgId
は親組織IDです。これで組織ツリーを表現しています。なお、親子関係を作るために親から先に登録していく必要があるため、CSVは親から子の順番でソートしたものを用意します。
orgId,orgName,parentOrgId
001,サンプル株式会社,
002,営業本部,001
003,総務本部,001
004,IT本部,001
005,営業第一部,002
006,営業第二部,002
007,総務部,003
008,IT開発部,004
009,ITインフラ部,004
010,営業第一課,005
011,営業第二課,006
上記内容のCSVファイルを作成し、hr
ディレクトリを作成してその配下にorgs.csv
として保存しておきます。これでmidPointからは、/var/lib/hr/orgs.csv
でCSVファイルにアクセス可能になります。
.
├── .env
├── docker-compose.yml
├── hr
│ ├── orgs.csv
│ └── users.csv
└── post-initial-objects
├── 000-system-configuration.xml
├── 100-resource-hr-users.xml
└── 900-task-hr-import-users.xml
midPointの起動
docker compose up -d
で環境を起動します。
リソース設定の追加
midPointの画面を操作して、5日目と同様にCSVをインポートするためのリソース設定を追加していきます。例によってシステム管理者(administrator
)でmidPointにログインし、設定作業を行います。
リソースの作成
基本的な作成手順は、5日目で解説したユーザー用の設定と同じです。詳しい操作内容は5日目を参照していただき、今回は、異なる部分を中心に補足説明します。
リソースの基本情報で設定する「名前」はリソース内で一意である必要があるため、今回はHR Orgs
としておきます。今回も、「ライフサイクル状態」は Active (production)
とします。
「File path」は先程配置したダミー組織のCSVファイルパスになります。/var/lib/hr/orgs.csv
を設定します。
CSVコネクターの設定は以下のようにします。
-
Field delimiter:
,
- User password attribute name:(空のまま)
-
Name attribute:
orgId
-
Unique attribute name:
orgId
コネクターがサポートするオブジェクトタイプは、組織であってもデフォルトで選択済みの「AccountObjectClass」を使用します。そのまま「リソースの作成」ボタンをクリックします。
組織なのにAccountObjectClass?と違和感があるかもしれません。CSVコネクターは1つのCSVファイルに1つのオブジェクトタイプのデータが格納されていることを想定して実装されています。この時のオブジェクトタイプは「AccountObjectClass」で固定化されています。ですが、ユーザーデータに限らないCSVファイルを利用しても問題ありません。最終的にmidPointの設定で、コネクター側のオブジェクトタイプ(今回だと「AccountObjectClass」)と、midPoint側のオブジェクトタイプ(今回だと「組織」)のマッピングをすれば問題ありません。
オブジェクト・タイプの追加
続いてオブジェクトタイプの追加です。組織を扱うため、今回は種類には エンタイトルメント
を選択しておきます。
オブジェクトタイプには、「アカウント」「エンタイトルメント」「汎用」の3つから、扱うデータとして適切な種類を割り当てればよいです。
-
表示名:
Org
-
種類:
エンタイトルメント
リソース・データの設定は、デフォルトのままで次に進みます。
MidPointデータの設定では、組織 を選択して保存します。この設定により、CSVから取り込んだデータはmidPoint内の組織(OrgType)オブジェクトにマッピングされます。
-
タイプ:
組織
マッピングの設定
以下の表を参考にインバウンドマッピングを設定します。parentOrgId
はXML編集で設定するため、「ターゲット」は今は未設定にしておきます。これで一旦保存します。
From Resource Attribute | 式 | ターゲット |
---|---|---|
orgId | 現状 | name |
orgName | 現状 | displayName |
parentOrgId | 現状 | (空) |
parentOrgId
より親組織をアサインするマッピングを設定
CSVでは親組織のIDをparentOrgId
列で表現しています。midPointの組織では、親組織をアサインすることで親子関係を表現できるようになりますので、このparentOrgId
の値を元に、親組織を探し出して自動アサインするようにマッピング設定を行います。
「指定した条件でオブジェクトを検索して、それをアサインとしてマッピング」を行う<assignmentTargetSearch>
という特別なタグがあるので、これを利用します。
作成したリソース設定の「RAWデータの編集」ボタンをクリックして、Raw編集画面を開きます。
parentOrgId
の<inboud>〜</inbound>
に、以下のようにXML設定を追加します。
<attribute id="11">
<ref>ri:parentOrgId</ref>
<inbound id="12">
<strength>strong</strength>
+ <expression>
+ <assignmentTargetSearch>
+ <targetType>c:OrgType</targetType>
+ <filter>
+ <q:equal>
+ <q:path>name</q:path>
+ <expression>
+ <queryInterpretationOfNoValue>filterNone</queryInterpretationOfNoValue>
+ <script>
+ <code>
+ input
+ </code>
+ </script>
+ </expression>
+ </q:equal>
+ </filter>
+ <assignmentProperties>
+ <subtype>HR</subtype>
+ </assignmentProperties>
+ </assignmentTargetSearch>
+ </expression>
+ <target>
+ <c:path>assignment</c:path>
+ <set>
+ <condition>
+ <script>
+ <code>
+ assignment?.subtype.contains("HR")
+ </code>
+ </script>
+ </condition>
+ </set>
+ </target>
</inbound>
</attribute>
<filter>
では、name
属性に対してinput
変数(<ref>
で設定したparentOrgId
の値が格納される)を使って一致検索を行うように設定しています。また、<queryInterpretationOfNoValue>filterNone</queryInterpretationOfNoValue>
の設定により、input
が値なしの場合(CSVのparentOrgId
が未設定の場合)に、filterNone
と評価されるようにしています。これにより、最上位のルート組織では、親組織の検索結果が0件、つまり何もアサインしないようにしています。
<assignmentProperties>
は、アサインに含めることができるメタデータを設定するためのタグです。今回、subtype
というメタデータ属性にHR
を設定しています。このアサインが源泉データ起因で行われたことが後から分かるように印をつけています。
<target>
では、アサインデータのマッピング先を設定しています。midPointの組織オブジェクトが持つassignment
属性に格納するように設定します。その中で重要なのが、<set>
の設定です。これは、7日目の記事で解説した高度なRange Mapping設定です。
assignment
属性は、組織が複数のアサインを持てるように、マルチバリュー項目になっています。CSVの組織データをインポートする際に、既存の親子関係を洗い替えるようにしないと、旧組織への親参照をもったままになってしまいます。よってここでは、Range Mappingを設定して洗い替えを行います。
しかしながら、7日目の記事で解説した<predefined>all</predefined>
を使うと、すべてのアサイン情報を洗い替えてしまいます。この組織にはロールなど別のオブジェクトをアサインする可能性もあるため、ここでは源泉データよりアサインされた親組織に絞って洗い替えができるとよさそうです。
ということで、Groovyスクリプトを使った高度なRange Mappingを行います。では、どのようにして「源泉データよりアサインされた親組織」を判断するとよいでしょうか? ここで役立つのが先程設定したメタデータです。アサインのsubtype
属性に、HR
という値を設定しているため、これを確認して判断すればよいです。subtype
はマルチバリュー項目のため、contains
メソッドを使っていずれかの値がHR
かどうかをチェックできます。この設定により、HR
をsubtype
に持つアサインは削除対象となり、洗い替えが期待通りに行われます。
同期の設定
ユーザーの時と同じ同期のルール設定をしておきます。
Correlationの設定
ユーザーの時と同じCorrelationのルール設定をしておきます。
組織のインポート
リソースの作成が完了しましたので、いよいよ組織をインポートします。5日目の記事で解説したとおり、インポートタスクでは源泉データの削除を検知して同期することができません。つまり、組織改正が行われて新しい組織データを取り込んでも、廃止した組織が消えずにそのまま残ってしまいます。そこで、6日目の記事「midPoint における源泉削除の同期処理」で解説したように、削除も同期できるように今回は「リコンシリエーションタスク」を作成して一括取り込みを行います。
リコンシリエーションタスクの作成
Reconciliation Task
を選択して、リコンシリエーションタスクを作成します。
区別が付くように名前を設定します。
-
名前:
HR recon orgs
「種類」は今回、リソースのオブジェクト・タイプの設定でエンタイトルメントとしているため、このタスクで利用する種類もエンタイトルメント
にする必要があります。
-
種類:
エンタイトルメント
-
用途:
default
-
オブジェクトクラス:
AccountObjectClass
スケジュールは、今回も空のままとします。
ワーカースレッドは1
を設定します。親から子の順番で処理しないと親子関係の設定に失敗するため、マルチスレッドでは処理しないようにしておきます。
リコンシリエーションタスクの実行
作成したリコンシリエーションタスクを実行すると、CSVより組織データがインポートされ、親子関係もできていることを確認できます。
組織改正
では、最後に組織改正のシナリオも試してみましょう。ここでもChatGPTを使って組織改正後のダミーデータを作ってもらいました。
というわけで、hr/orgs.csv
を以下の内容に置き換えます。
orgId,orgName,parentOrgId
001,サンプル株式会社,
002,営業統括本部,001
003,管理本部,001
004,デジタル戦略本部,001
005,法人営業部,002
006,個人営業部,002
007,総務・人事部,003
008,ITソリューション部,004
009,インフラ運用部,004
012,営業推進課,005
013,DX推進課,004
014,新規事業部,001
これで再度リコンシリエーションタスクを実行します。実行完了後、組織ツリーを確認すると組織改正後の状態になっていることを確認できます。
監査ログも確認してみましょう。リソース設定にて、同期の設定で「状況(Situation)が Deleted」の場合にフォーカス削除としているため、リコンシリエーションタスクを使用することで、廃止組織(orgId
が010
と011
の組織)がmidPointから削除されていることが分かります。
まとめ
8日目では、組織情報を含むCSV形式の源泉データを、midPointの組織オブジェクトとしてインポートするための設定を紹介しました。また、6日目の記事と7日目の記事で補足説明した設定を利用して、組織改正にも対応させました。
これでユーザーと組織を源泉データよりmidPointに取り込むことができるようになりました!しかし、お気付きかもしれませんが、midPoint上でユーザーと組織の関連付け(アサイン)がまだ行われていません。次回はこのあたりの設定追加を行います。お楽しみに!