midPointにおける「アクセス認定」実践編

# はじめに
midPointアドベントカレンダー13日目の[midPointにおける「アクセス認定」](https://qiita.com/tama1/private/1e1f3e42802a338bf41a)で、midPointのアクセス認定の概要について紹介しました。
midPointアドベントカレンダー14日目の今回は、実際にキャンペーン定義を作成して動かしてみます。

#準備
キャンペーン定義の作成や、スケジュールの設定、通知の設定を行います。

##キャンペーン定義作成
今回は、有効期限が迫っているユーザーを、所属組織の管理者が確認する、というシナリオで定義を作成していきます。

最初からXMLで全て作成するのは大変なので、画面から作成してみましょう。
メニューから、検証（Certification） -> 新規キャンペーン定義（New campaign definition）をクリックすると、キャンペーン定義の登録画面が開きます。

###基本情報／Basic
キャンペーンの基本情報を登録します。
![2_基本情報.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533134/dc38849b-0155-3962-c3b3-d10c5464208a.jpeg)


####設定項目

|項目名|内容|
|:--------|:--------|
|名前<br>／Name|必須項目です。キャンペーンの名前を設定します。|
|オーナー<br>／Owner|各ステージでのレビューの結果をまとめた最終的な決定の判断基準を設定します。設定値の詳細な説明は、後述します。|
|ステージの結果から全体的な結果を導き出すためのストラテジー<br>／Strategy for deriving overall outcome from stage outcomes|各ステージでのレビューの結果をまとめた最終的な決定の判断基準を設定します。設定値の詳細な説明は、後述します。|
|修復<br>／Remediation|レビューステージが全て完了した後に、結果をターゲットに反映する場合は、自動リコンシリエーションを選択します。<br>レビュー結果が、取り消し(Revoke)になった場合、オブジェクトからターゲットのアサインが外れます。それ以外は、該当の`assignment`のメタ情報として、キャンペーン結果と実行日時、レビューワーが設定されます。<br>データの削除やその他の項目の更新はできないので、結果をもとに別のタスクで対応しましょう。|
|キャンペーン終了後の自動繰り返し<br>／Automatic reiteration after campaign close|キャンペーンを定期的に繰り返したい場合、キャンペーン終了からの次の開始までの間隔を設定します。<br>キャンペーン期間が7日間で、15日後に次回を開始した場合などは、`P15D`と設定します。毎月1日に開始したいという場合は、次回までの日数が毎月かわるのでスケジュールで設定します。|
|自動反復回数の制限<br>／Limit for automatic iterations|自動繰り返しを設定した場合に、繰り返しの上限を設定できます。制限しない場合は設定する必要はありません。|
|全体の反復回数制限<br>／Overall iterations limit|キャンペーン定義から作成したキャンペーンを実施する上限を設定できます。|

####ストラテジーの種類
+ **どんな”承諾”も受け入れる(oneAcceptAccepts)：**　レビュワーのうち1人でも承諾(Accept)とすれば、結果は承諾になります。
+ **すべてのレビューワーが受け入れる場合にのみ受け入れられる(allMustAccept)：**　全てのレビューワーが承諾とした場合のみ、結果は承諾になります。
+ **どんな”拒否”も拒否する(oneDenyDenies)：**　レビュワーのうち1人でも取り消し(Revoke)とすると、結果は取り消しになります。取り消しがなく、1人でも削減(Reduce)とした場合は、結果は削減になります。
+ **誰も拒否しなければ受け入れる(acceptedIfNotDenied)：**　取り消しや削減がなければ、結果は全て承諾になります。

設定したストラテジーにあわせて、どの判断が優先されるかは、wikiの[Determining Certification Case Outcome](https://wiki.evolveum.com/display/midPoint/Determining+Certification+Case+Outcome)にマトリクスがあるので参考にしてください。

基本情報の設定は、XMLでこんな感じになります。

```xml
    <accessCertificationDefinition 
        xmlns="http://midpoint.evolveum.com/xml/ns/public/common/common-3"
        xmlns:c="http://midpoint.evolveum.com/xml/ns/public/common/common-3"
        xmlns:icfs="http://midpoint.evolveum.com/xml/ns/public/connector/icf-1/resource-schema-3"
        xmlns:org="http://midpoint.evolveum.com/xml/ns/public/common/org-3"
        xmlns:q="http://prism.evolveum.com/xml/ns/public/query-3"
        xmlns:ri="http://midpoint.evolveum.com/xml/ns/public/resource/instance-3"
        xmlns:t="http://prism.evolveum.com/xml/ns/public/types-3">
        <name>有期雇用社員有効期限確認</name>
        <description>有効期限まで1か月以内のユーザーを確認します</description>
        <handlerUri>http://midpoint.evolveum.com/xml/ns/public/certification/handlers-3#direct-assignment</handlerUri>
        <scopeDefinition  xsi:type="AccessCertificationAssignmentReviewScopeType">
            …
        </scopeDefinition>
        <ownerRef oid="00000000-0000-0000-0000-000000000002" relation="org:default" type="c:UserType">
            <!-- administrator -->
        </ownerRef>
        <remediationDefinition>
            <style>automated</style>
        </remediationDefinition>
        <stageDefinition>
            …
        </stageDefinition>
        <reviewStrategy>
            <outcomeStrategy>oneAcceptAccepts</outcomeStrategy>
        </reviewStrategy>
    </accessCertificationDefinition>
```

###スコープ定義／Scope definition
キャンペーンのスコープを登録します。
今回のシナリオでは、有効期限が迫っているユーザーがスコープになります。
派遣社員ロールとパートナー社員ロールがアサインされているユーザーには、有効期限が設定されているということにして進めます。
![3_スコープ定義.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533134/7a141da5-a78a-135d-1102-d76ea186b570.jpeg)

####設定項目

|項目名|内容|
|:--------|:--------|
|スコープ名<br>／Scope name|スコープ名を設定します。|
|オブジェクトタイプ<br>／Object type|今回は対象がユーザーなので、ユーザーを選択します。|
|選択オブジェクトをフィルターする<br>／Filter to select objects|スコープのオブジェクトを絞り込むための`searchFilter`のタグを設定できます。|
|アサインまたはインデュースメントを含める<br>／Include assignments or inducements|オブジェクトとターゲットの関連を設定します。<br>アサインとインデュースメントのいずれか、または両方にチェックします。何もチェックされていない場合は、レビュー対象が抽出されません。|
|ターゲットタイプを含める<br>／Include target types|今回は、特定のロールにひもつく設定の確認になるので、ロールをターゲットにします。キャンペーンの目的にあわせてターゲットは設定しましょう。|
|アクティベーション・ステータスで含める<br>／Include by activation status|チェックすると、ターゲットに設定したもののうち、アクティベーション・ステータスが`active`、または未設定のものだけを抽出します。|
|リレーション<br>／Relation|ターゲットのリレーションを設定します。<br>今回はデフォルトですが、組織にリレーションを`manager`でアサインしたユーザーのみとしたい場合などはマネージャーを設定します|

ここまでの設定で、XML定義はこんな感じになります。

```xml
    <scopeDefinition xsi:type="c:AccessCertificationAssignmentReviewScopeType">
        <name>有期雇用社員ユーザー</name>
        <description>有期雇用社員の各ロールがアサインされたユーザーのうち、有効期限が1か月以内</description>
        <objectType>UserType</objectType>
        <includeAssignments>true</includeAssignments>
        <includeInducements>false</includeInducements>
        <includeResources>false</includeResources>
        <includeRoles>true</includeRoles>
        <includeOrgs>false</includeOrgs>
        <includeServices>false</includeServices>
        <includeUsers>false</includeUsers>
        <enabledItemsOnly>false</enabledItemsOnly>
        <relation>org:default</relation>
    </scopeDefinition>
```

スコープの絞り込み条件をさらに細かく設定した場合は、XMLを編集しましょう。
**searchFilter** では、オブジェクトを取得するためのクエリに条件を設定できます。（今回はつかいません。）
**itemSelectionExpression** は、取得したオブジェクトが条件に一致するかどうか判定するために設定します。ここでは、`assignment`と`focus`（オブジェクトがUserTypeの場合`user`でも可）がオブジェクトとして使用できます。今回は、対象とするロールと、アクティベーションの終了日時に条件を設定してみました。

```xml
    <scopeDefinition>
        …
        <itemSelectionExpression>
            <script>
                <code>
                   role = midpoint.resolveReferenceIfExists(assignment.targetRef)
                   if (role.name.toString() == 'dep-partner' || role.name.toString() == 'dep-temp') {
                       if (focus.activation?.validTo.compare(basic.fromNow('P1M')) &lt;= 0) {
                           return true
                       }
                   }
                   return false
               </code>
            </script>
        </itemSelectionExpression>
    </scopeDefinition>
```

###ステージ定義／Stage definition
レビューステージの設定を行います。
![4_ステージ定義.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533134/d355d150-1bb5-d1b4-3850-c3642de8dc7c.jpeg)

####設定項目

|項目名|内容|
|:--------|:--------|
|名前<br>／Name|ステージ名を設定します。|
|期間<br>／Duration|ステージの開始から終了までの期間を設定します。|
|通知<br>／Notify before deadline|ステージ終了前にリマインド通知を送信するタイミングを設定します。<br>終了の3日前や24時間前といった設定ができます。カンマ区切りで複数設定が可能です。|
|決定を下さない場合にのみ通知する<br>／Notify only when no decision|レビュー結果を入力していない場合にのみリマインド通知を行う場合はチェックします。|
|割当て対象オブジェクトのレビューワー<br>／Reviewers based on assignment target object|ターゲットのオーナーや承認者(Approver)にリレーションされているユーザーをレビューワーにする場合はチェックしましょう。|
|このオブジェクトに割当てられているレビューワー<br>／Reviewers based on the object being assigned to|オブジェクトのオーナーや承認者(Approver)にリレーションされているユーザーをレビューワーにする場合はチェックしましょう。|
|このオブジェクトに割当てられているマネージャーに基づくレビューワー<br>／Reviewers based on the manager of object being assigned to|オブジェクトの管理者(Manager)にリレーションされているユーザーをレビューワーにする場合はチェックしましょう。<br>オブジェクトがユーザーの場合は、ユーザーの所属組織の管理者がレビューワーになります。オブジェクトがロールとサービスの場合はこの設定は有効になりません。<br>今回はここにチェックします。|
|マネージャを決定するために使用される組織関係のタイプ<br>／Type of organization relation used to determine the manager|組織の管理者をレビューワーにする場合、対象となる組織をSubtypeで指定することができます。<br>会社の実組織とプロジェクトごとの組織のように、ユーザーが複数タイプの組織に所属している場合に利用します。|
|複数のレビューワーの場合の決定集約ストラテジー<br>／Decision aggregation strategy in case of more than one reviewer|このステージでのレビューの結果をまとめた最終的な決定の判断基準を設定します。<br>設定値の内容は、基本情報のステージの結果から全体的な結果を導き出すためのストラテジーと同じです。|

ここまでで、XML定義はこんな感じです。

```xml
    <stageDefinition>
        <number>1</number>
        <name>Stage 1</name>
        <description>有期雇用社員が所属する組織の管理者が有効期限を延長するかどうか確認します。</description>
        <duration>P7D</duration>
        <notifyBeforeDeadline>P3D</notifyBeforeDeadline>
        <notifyBeforeDeadline>PT24H</notifyBeforeDeadline>
        <notifyOnlyWhenNoDecision>false</notifyOnlyWhenNoDecision>
        <reviewerSpecification>
            <useTargetOwner>false</useTargetOwner>
            <useTargetApprover>false</useTargetApprover>
            <useObjectOwner>false</useObjectOwner>
            <useObjectApprover>false</useObjectApprover>
            <useObjectManager>
                <allowSelf>false</allowSelf>
            </useObjectManager>
        </reviewerSpecification>
        <outcomeStrategy>oneAcceptAccepts</outcomeStrategy>
        <outcomeIfNoReviewers>reduce</outcomeIfNoReviewers>
    </stageDefinition>
```


特定組織に所属しているユーザーや特定ロールがアサインされたユーザーなど、オブジェクトやターゲットのオーナーや承認者、管理者ではないユーザーをレビューワーとしたい場合は、XMLを編集して、**reviewerExpression**の設定を追加します。
スクリプトが使用できるので、いろいろな条件に対応できます。
スクリプト内では、`certificationCase`がオブジェクトとして使用することができます。キャンペーンの詳細ケースのオブジェクトなので、ここからオブジェクトやターゲットの情報を取得することができます。

ステージ定義は複数設定することができます。最初に所属組織の管理者、次に上位組織の管理者が確認するというような場合、レビューステージを追加しましょう。ステージ定義の`number`に設定された数値の順序で実行されます。

また、1つのステージの中で、ステージ開始から〇日後にはレビューワーを追加するとか、レビューワーを交代するといったこともできます。その場合は、ステージ定義に**timedActions**を設定します。詳細は、wikiの[Escalation in certification campaigns HOWTO](https://wiki.evolveum.com/display/midPoint/Escalation+in+certification+campaigns+HOWTO)を参考にしてください。

ここまでで、いったんキャンペーン定義は作成できました。
ここからは、キャンペーンを実行するために、それ以外の設定をしていきましょう。

##通知設定
キャンペーンのステージ定義でリマインド通知の設定をしたので、通知の設定を行いましょう。
今回は、メールでの通知とします。
前提として、システムメニューの通知タブで、メール設定をしておいてください。

**systemConfiguration**のXMLを編集します。キャンペーン開始とリマインド通知は、**simpleReviewerNotifier**で設定します。最低限`<transport>mail</transport>`だけ設定しておけば、デフォルト文面のメールがレビューワーに送信されます。

```xml
    <notificationConfiguration>
        …
        <handler>
            <simpleReviewerNotifier>
                <transport>mail</transport>
            </simpleReviewerNotifier>
        </handler>
    </notificationConfiguration>
```

その他のキャンペーン関連の通知やデフォルトの文面は、wikiの[Access Certification Notifications](https://wiki.evolveum.com/display/midPoint/Access+Certification+Notifications)を参考にしてください。
日本語メールを送信するなど、通知内容のカスタマイズをしたい場合は、上記の設定に追加してください。


##スケジュールタスクの設定
キャンペーン定義から、キャンペーンの作成・開始は画面からもできますが、自動で実行できるようにスケジュールタスクを作成します。

残念ながら、サーバータスクのメニューから画面で作成することができないカテゴリなので、XMLで定義を作成してインポートします。

```xml
    <task
        xmlns="http://midpoint.evolveum.com/xml/ns/public/common/common-3"
        xmlns:q="http://prism.evolveum.com/xml/ns/public/query-3">

        <name>有期雇用社員有効期限確認の実施</name>
        <category>AccessCertification</category>
        <ownerRef oid="00000000-0000-0000-0000-000000000002"/>
        <handlerUri>http://midpoint.evolveum.com/xml/ns/public/certification/task/campaign-creation/handler-3</handlerUri>
        <objectRef type="AccessCertificationDefinitionType">
            <filter>
                <q:equal>
                    <q:matching>polyStringOrig</q:matching>
                    <q:path>name</q:path>
                    <q:value>有期雇用社員有効期限確認</q:value>
                </q:equal>
            </filter>
        </objectRef>
        <executionStatus>runnable</executionStatus>
        <recurrence>recurring</recurrence>
        <binding>loose</binding>
        <schedule>
            <cronLikePattern>0 0 0 1 * ?</cronLikePattern>
        </schedule>
    </task>
```


+ **category：**　`AccessCertification`を設定します。
+ **handlerUri：**　`http://midpoint.evolveum.com/xml/ns/public/certification/task/campaign-creation/handler-3`を設定します。
+ **objectRef：**　作成したキャンペーン定義のオブジェクトを設定します。
+ **schedule：**　今回は、毎月1日の0時に開始するように、Cron-like仕様で設定しました。

##利用可能な応答の設定
デフォルトでは、判定結果の選択肢は、`承諾(Accept)`、`取り消し(Revoke)`、`削減(Reduce)`、`未定(Not Decided)`、`応答無し(No Response)`の5種類あります。判定の選択肢を限定したい場合には、システムメニューから設定しましょう。

システムメニューの認定のアクセスタブを開きます。利用可能な応答で、必要な判定のみ登録します。ここで設定した順序で表示されます。
![システムー認定のアクセス.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533134/c0082f40-2638-3956-4ec6-9a72d6e6bf6b.jpeg)

この設定は、レビューワーの作業アイテムの画面だけではなく、実行中のキャンペーンの詳細画面にも適用されます。キャンペーン開始時には、全てのケースが`応答無し(No Response)`の状態となっているため、選択肢に応答無しが入っていないと、キャンペーンの詳細画面の表示がおかしくなります。(※v.4.0.1時点)
また、全てのキャンペーンに共通の設定になるので、キャンペーンにより設定を変更することができません。どのキャンペーンのときに、レビューワーにどういう判定をしてほしいのかを周知しないと、キャンペーン終了後に思わぬところでロールや組織のアサインが外れてしまって大騒ぎ、ということになりかねません。

##レポート定義
今回は、初期設定に入っているレポートを使用します。wikiの[Access Certification Reports](https://wiki.evolveum.com/display/midPoint/Access+Certification+Reports)を参照してください。


#キャンペーンの実行
キャンペーンを実行するための準備ができたので、実行してみます。

##スケジュール実行
毎月1日の0時に開始するように設定したので、期日がきたらなにもしなくても実行されますが、動作確認と思って動かしてみましょう。

キャンペーンのスケジュールリングメニューを開くと、登録したスケジュールが表示されています。右端のボタンから、今すぐ実行を選択します。
![スケジュール_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533134/3476d0d0-414e-34e2-b3a1-b40a550ec4b2.jpeg)

これでキャンペーン定義からキャンペーンが作成されて、開始されました。
キャンペーンの名称は、キャンペーン定義の基本情報で設定した名前に、実行回数のカウントがついています。
システム管理者は、キャンペーンの詳細画面で、各ケースのレビュー状況を確認できます。
![キャンペーン開始.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533134/be3504ba-8996-3771-3318-ab7b26c0dcee.jpeg)

開始と同時に、リマインド通知と、ステージのクローズのトリガーも登録されているの、期日がくると自動で実行されます。

##レビューの実施

開始と同時に、レビューワーには、通知メールが送信されています。
![通知メール.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533134/02558b1d-05c1-8e0c-42a6-18ccadbefeb0.jpeg)

レビューワーは、メールをみて、レビューを実施してくれるはずです。
ステージの実施期間中、レビューワーは何回でも判定結果を変更することができます。
![レビュー.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533134/aa0cb694-cb8a-9df2-da25-58f66cf35ea7.jpeg)

##修復／Remediation
ステージの実施期間が過ぎて自動でクローズされ、次のステージがない場合は、修復の処理が自動で開始されます。
今回、自動リコンシリエーションを選択したので、レビュー結果がターゲットのメタ情報に反映されています。
ユーザーのXML情報をみると、ターゲットになっていたロールのアサイン情報にこんな感じで認定結果が入ってます。

```xml
    <assignment>
        <metadata>
            …
            <certificationFinishedTimestamp>2019-12-05T19:25:12.869+09:00</certificationFinishedTimestamp>
            <certificationOutcome>http://midpoint.evolveum.com/xml/ns/public/model/certification/outcome#accept</certificationOutcome>
            <certifierRef oid="fcd6a119-161a-44c2-a5d8-4687b81cd68c" relation="org:default" type="c:UserType">
                <!-- u00001 -->
            </certifierRef>
        </metadata>
        <targetRef oid="db40d63c-9ce5-42fd-a8fb-2f174a137c0a" relation="org:default" type="c:RoleType">
            <!-- dep-temp -->
        </targetRef>
        <activation>
            <effectiveStatus>enabled</effectiveStatus>
        </activation>
    </assignment>
```

+ **certificationFinishedTimestamp：**　キャンペーン終了の日時です。
+ **certificationOutcome：**　最終的な判定結果が設定です。
+ **certifierRef：**　レビューワーの`oid`が設定されます。

今回は用意していませんが、`certificationOutcome`に`http://midpoint.evolveum.com/xml/ns/public/model/certification/outcome#accept`が設定されているユーザーの有効期限を3か月後に更新する、といったスケジュールタスクを作成することができます。

自動リコンシリエーションの処理はレビュー結果により変わります。
レビュー結果が`取り消し(Revoke)`となった場合は、自動リコンシリエーションが行われると、オブジェクトからターゲットのアサインが解除されます。今回の場合だとロールのアサインがはずれます。これを利用して、特定のロールのアサインがないユーザーは`lifecyclestate`を無効(disabled)にするといったスケジュールタスクを設定しておくといった対応が可能です。

####レビュー結果と自動リコンシリエーション

|レビュー結果|Outcome|自動リコンシリエーションの処理|
|:--------|:-------------------------------------------|:--------|
|承諾(Accept)|`http://midpoint.evolveum.com/xml/ns/public/model/certification/outcome#accept`|オブジェクトのアサインのメタ情報に設定される|
|取り消し(Revoke)|`http://midpoint.evolveum.com/xml/ns/public/model/certification/outcome#revoke`|オブジェクトからターゲットのアサインが解除されます|
|削減(Reduce)|`http://midpoint.evolveum.com/xml/ns/public/model/certification/outcome#reduce`|オブジェクトのアサインのメタ情報に設定される|
|未定(Not Decided)|`http://midpoint.evolveum.com/xml/ns/public/model/certification/outcome#notDecided`|オブジェクトのアサインのメタ情報にはなにも設定されません|
|応答無し(No Response)|`http://midpoint.evolveum.com/xml/ns/public/model/certification/outcome#noResponse`|オブジェクトのアサインのメタ情報にはなにも設定されません|

##レポート出力
キャンペーンの実行結果をレポート出力しましょう。
レポートメニューのすべてのレポートの画面で、登録されているレポート定義から出力するレポートを選択します。
レビュー結果を見たいので、**Certification cases report** か **Certification decisions report** を出力します。前者はストラテジーの設定による最終的な判定結果が出力されます。後者は、各レビューワーごとの個別の判定結果が全て出力されます。

キャンペーン名をパラメータに入力して（プルダウンで候補がでます）、実行ボタンを押しましょう。
![レポート出力_1.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533134/2dc5c8be-7f64-331b-b47d-4639b3e22689.jpeg)

作成されたレポートの画面で、出力したレポートをダウンロードすることができます。
初期登録されているキャンペーンのレポートはHTMLで出力されるようになっているのでそのままブラウザで確認できます。
![レポート.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533134/015a8a7d-3659-9692-cbdd-29b37b3216b1.jpeg)

レポートの出力フォーマットは、編集画面で簡単に変更できます。CSVやPDF、Excel形式、Word形式など、好きな形式に変更して出力しましょう。

#まとめ
今回作成したキャンペーン定義は、ごく簡単な設定だったので、画面からの設定でほとんどの設定を行うことができました。
実際には、IDライフサイクルや、エンタイトルメント、ロールの設計にあわせて、キャンペーンの目的を決めて、さらにスコープやステージの設定を行うので、条件が複雑になることが想定されます。
midPointに付属のサンプルは、そこまで複雑な設定のものはありませんが、SearchFilter や Expression の書き方は、他の機能とたいして変わらないので、参考になるものはいろいろあるかと思います。