3.5.2.2 テンプレート文字列での割り当て
アイデンティティプロバイダーマッピング画面では外部IdpとOps Iのマッピング規則を設定します。テンプレート文字列で割り当てると、条件の値、Claim(OIDCの場合)、および属性(SAMLの場合)と、Ops Iのグループ、ロール、および属性が完全に一致しない場合もマッピング対象として指定できます。その結果、マッピングを複数登録しなくても、さまざまな条件を満たす対象を一度に設定できます。
ここでは次の項目について説明します。
(1)記載ルール、例
テンプレート文字列での割り当てには、ディレクティブ、出力式、条件式、演算子、文字列向け関数、シーケンス向け関数が使用できます。
ここで、varは任意の変数、strは任意の文字列、listは任意のシーケンスを意味します。
【ディレクティブ】
使用できるディレクティブは次の通りです。
| ディレクティブ | 説明 | 使用例 |
|---|---|---|
| <#-- コメント --> | コメントの記載 | <#-- コメント --> |
| <#if>...</#if> <#if>...<#elseif>...<#else>...</#if> |
条件分岐 | <#if>...<#elseif>...<#else>...</#if> |
| <#assign var = "A"> | 変数を定義 | <#assign var = "A"> |
| <#list items as item>...</#list> | listの中の値に個別処理を定義 | <#list items as item>...</#list> |
【出力式】
使用できる出力式は次の通りです。
| 出力式 | 説明 | 使用例 |
|---|---|---|
| ${} | 変数を出力 | ${} |
【条件式】
使用できる条件式は次の通りです。
| 条件式 | 説明 | 使用例 |
|---|---|---|
| var?? | 変数が存在するかどうかを確認 | var?? |
| var?has_content | 変数が存在し、かつその値が空でないかどうかを確認 | var?has_content |
【演算子】
使用できる演算子は次の通りです。
| 演算子 | 説明 | 使用例 |
|---|---|---|
| == | 等しい | == |
| ! | 否定 | ! |
| != | 等しくない | != |
| || | または | || |
| && | かつ | && |
| lt | <(未満) | lt |
| lte | <=(以下) | lte |
| gt | >(超過) | gt |
| gte | >=(以上) | gte |
【文字列向け関数】
使用できる文字列向け関数は次の通りです。
| 文字列向け関数 | 説明 | 使用例 |
|---|---|---|
| str?c_lower_case | 小文字にそろえる | str?c_lower_case |
| str?c_upper_case | 大文字にそろえる | str?c_upper_case |
| str?replace("A", "B") | Aの文字列をBの文字列に置き換える | str?replace("A", "B") |
| str?split("A") | 指定した文字列をAで分割し、リスト型で出力 | str?split("A") |
| str?date("yyyy-MM-dd") | 日付型に変換し、演算子ltやgtで日付を比較 | str?date("yyyy-MM-dd") |
| str?number | 数値型に変換 | str?number |
| str?trim | 前後の空白を削除 | str?trim |
| str?contains("A") | 文字列にAを含むかどうかを確認 | str?contains("A") |
| str?starts_with("A") | 文字列がAで始まるかどうかを確認 | str?starts_with("A") |
| str?ends_with("A") | 文字列がAで終わるかどうかを確認 | str?ends_with("A") |
| str?matches("A") | Aの形式の正規表現になっているかどうかを確認 | str?matches("A") |
【シーケンス(配列、リスト)向け関数】
使用できるシーケンス向け関数は次の通りです。
| シーケンス向け関数 | 説明 | 使用例 |
|---|---|---|
| list?seq_contains("A") | シーケンスが特定の要素Aを含むかどうかを確認 | list?seq_contains("A") |
| list?join("A") | シーケンスの要素をAで結合し、単一の文字列を出力 | list?join("A") |
外部Idp側の情報を指定する際に、外部IdP側の情報が格納されているauthn_infoを使用できます。
SAMLとOIDCではauthn_infoで使用できるユーザー情報と使用方法が異なります。それぞれのauthn_infoの特徴は次の通りです。
①SAMLの場合:
- Attributeに含まれる情報を使用できる
- 配列の中のどの要素を参照するか、インデックスで指定する必要がある
<#if authn_info["preferred_username"][0]=="test_user">
メモ外部Idp側からの格納順が不明なため、?seq_contains()などの使用を推奨します。
②OIDCの場合:
- IDトークンまたはUserInfoエンドポイントから取得できるユーザー情報に含まれるプロパティを使用できる
<#if authn_info["preferred_username"]=="test_user">
注意事項
- ユーザー属性に「顧客」を設定する場合、顧客IDを指定してください。
- 1つの属性とのマッピング設定を複数作成しないでください。
マッピングされる順序は不定のため、属性の設定値が意図した値にならないことがあります。 - キーの階層構造はブラケット記法で記載してください。
例:上位階層[下位階層] - グループ属性、ロール属性は複数指定できます。このとき、指定する値は改行で区切ってください。また、ユーザー属性は2つ以上指定することがないため、複数指定しないでください。
- テンプレートで指定可能な上限文字数は10,000文字です。
- テンプレートで出力可能な上限文字数は10,000文字です。10,000文字以上出力された場合、エラーメッセージが出力されログインできません。その場合、Ops I セキュリティ管理者はループ処理を中心にテンプレート文字列を見直してください。
- 先頭、および末尾の空白は削除されます。
- ディレクティブの中では、ダブルクォーテーション(")やシングルクォーテーション(')で文字列を囲ってください。
- ディレクティブの外では、ダブルクォーテーション(")やシングルクォーテーション(')で文字列を囲まないでください。意図しない割り当てとなってしまうおそれがあります。
- authn_infoから返される数値は、数値型ではなく、文字列型であることがあります。文字列型の場合、数値型で使用できる操作を行えません。
- 出力式「${}」は、ディレクティブの中では使用しないでください。
ディレクティブ、出力式、条件式、演算子、文字列向け関数、シーケンス向け関数を使用した例は以下の通りです。
「改行付きでロールを出力」というコメントを記載
<#if authn_info["role"]??>
${authn_info["role"]?join("\n")}
</#if>
<#if>...<#elseif>...<#else>...</#if>
外部IdPの「id」が「1」の場合は「adminGroup1」を、「2」の場合は「adminGroup2」を、それ以外の場合は「customerGroup」のロールを割り当てる
adminGroup1
<#elseif authn_info["id"] == "2">
adminGroup2
<#else>
customerGroup
</#if>
外部IdPの「department」が「abc」という文字列でない場合、「portal_subscriber」ロールを割り当てる
<#if !condition1>
portal_subscriber
</#if>
<#list items as item>...</#list>
リスト型で格納されている外部IdPの「role」情報をそれぞれ確認し、文字列の一部に「admin」という文字列が含まれている場合、「user_admin」と「customer_admin」を割り当てる
<#if rolename?contains("admin")>
user_admin
customer_admin
</#if>
</#list>
外部IdP側の「email」情報が空でない場合、「email」情報をそのまま割り当てる
${authn_info["email"]}
</#if>
外部IdP連携をしている場合、「idp_user」グループを割り当てる
idp_user
</#if>
外部IdP側の「email」情報が空でない場合、「email」情報をそのまま割り当てる
${authn_info["email"]}
</#if>
外部IdPの「groups」以下の「customer.group」が「portal」という文字列である場合、「portal_subscriber」ロールを割り当てる
portal_subscriber
</#if>
外部IdPの「department」が「abc」という文字列でない場合、「portal_subscriber」ロールを割り当てる
<#if !condition1>
portal_subscriber
</#if>
外部IdPの「customer」が「123」という文字列でない場合、「customer_group」グループを割り当てる
customer_group
</#if>
外部IdPの「groups」がリストの中に「group 1」を持つか、「role」がリストの中に「author」を持つ場合、「portal_author」ロールを割り当てる
portal_author
</#if>
外部IdPの「groups」がリストの中に「group 2」を持ち、かつ「email」が「abc.com」である場合、「portal_site_admin」ロールを割り当てる
portal_site_admin
</#if>
外部IdPの文字列型だが数値である「customer(顧客コード)」を数値型に変換し、それが2000より小さい場合、「customer_group」グループを割り当てる
customer_group
</#if>
外部IdPの文字列型だが数値である「customer(顧客コード)」を数値型に変換し、それが2000以下の場合、「customer_group」グループを割り当てる
customer_group
</#if>
外部IdPの文字列型だが数値である「customer(顧客コード)」を数値型に変換し、それが2000より大きい場合、「customer_group」グループを割り当てる
customer_group
</#if>
外部IdPの文字列型だが数値である「customer(顧客コード)」を数値型に変換し、それが2000以上の場合、「customer_group」グループを割り当てる
customer_group
</#if>
外部IdPの「username」を小文字に変換し、それが「hitachi_taro」と等しい場合、「customer_admin」ロールを割り当てる
customer_admin
</#if>
外部IdPの「username」を大文字に変換し、それが「HITACHI_TARO」と等しい場合、「customer_admin」ロールを割り当てる
customer_admin
</#if>
外部IdPの「groups」以下の「customer.group」が「hitachi」という文字列を含んでいる場合、その名前の「hitachi」部分を「test」に置き換えた名前のロールを割り当てる
${authn_info["groups"]["customer.group"]?replace("hitachi", "test")}
</#if>
外部IdPに「name」情報があり、かつその値が空でなく、「" "」で区切られている場合、それで区切った初めの値を姓として扱う
${authn_info["name"]?split(" ")[0]}
</#if>
外部IdPの生年月日情報(yyyy-MM-ddの形で格納されている)が2000年1月1日より前である場合、「century_group」グループを割り当てる
century_group
</#if>
外部IdPの文字列型だが数値である「customer(顧客コード)」を数値型に変換し、それが2000より大きい場合、「customer_group」グループを割り当てる
customer_group
</#if>
外部IdPの顧客情報が空でない情報を持っており、値が2000と等しい場合、「idp_user」グループを割り当てる
idp_user
</#if>
外部IdPの「email」が「hitachi」という文字列を含む場合、「hitachi_group」グループを割り当てる
hitachi_group
</#if>
外部IdPの「username」が「admin」という文字列で始まっている場合、「itsm_admin」ロールを割り当てる
itsm_admin
</#if>
外部IdPの「email」が「.com」という文字列で終わっている場合、外部IdPの「email」をOps Iの「email」として用いる
${authn_info["email"]}
</#if>
外部IdPの「customer(顧客コード)」が数字で構成されている場合、その顧客コードを割り当てる
${authn_info["customer"]}
</#if>
外部IdPで複数ロールを持つうちの1つに「admin」ロールを持っている場合、「itsm_admin」ロールを割り当てる
itsm_admin
</#if>
外部IdPに「role」情報がある場合、その同名ロールをOps Iで割り当てる
${authn_info["role"]?join("\n")}
</#if>
(2)テンプレート記載に対するエラー
テンプレートの記載に不備がある場合、以下のタイミングでエラーが出力されます。
【アイデンティティプロバイダーの保存時】
文法上の誤りがある場合、アイデンティティプロバイダーの保存時にエラーメッセージが表示されます。
エラーメッセージに記載された「[詳細]」を確認することで、問題のある行を特定できます。
<例>
構文エラーがある場合
KNBA00300-E
[詳細] エラーが発生した行
【ユーザーがログインするとき】
文法以外の不備があり、外部IdpとOps Iとの間で連携がうまくいかなかった場合、ユーザーのログイン時にエラーメッセージが表示されます。
ロールの割り当て時に、該当するロールが存在しない場合
グループの割り当て時に、該当するグループが存在しない場合
1つのユーザー属性に複数の値が割り当てられようとしている場合
メールアドレスの割り当て時に、予約ユーザーのメールアドレスが割り当てられようとしている場合
必須属性※に空の値が割り当てられようとしている場合
テンプレートで出力可能な上限文字数である10,000文字を超えた場合
不備の内容によって、以下のメッセージが出力されます。割り当てられるメールアドレスの認証の流れは「(図)外部IdPとOps Iに同一と判断されるユーザーが存在する場合に、外部IdPでログインする」を参照してください。
(3)よくある間違い
テンプレートの記載でよくある間違いと正しい記載の例を以下に示します。
- 顧客を指定する場合、顧客名ではなく顧客IDで指定してください。
<誤><#if authn_info["customer"] == "customer1"><正>
customer1
</#if><#if authn_info["customer"] == "customer1">
1001
</#if> - グループを割り当てる場合、改行で指定してください。
<誤><#if authn_info["group"]??><正>
${authn_info["group"]}
</#if><#if authn_info["group"]??>
${authn_info["group"]?join("\n")}
</#if> - ロールを割り当てる場合、改行で指定してください。
<誤><#if authn_info["id"] == "1"><正>
System Security Administrator, user_admin
</#if><#if authn_info["id"] == "1">
System Security Administrator
user_admin
</#if> - SAMLの場合、配列の中のどの要素を参照するか、インデックスで指定してください。
- テンプレートで属性(顧客)を割り当てる場合
<誤><#if authn_info["customer"] == "customer1"><正>
1001
</#if><#if authn_info["customer"][0] == "customer1">
1001
</#if> - テンプレートでロールを割り当てる場合
<誤><#if authn_info["username"]?c_upper_case == "HITACHI_TARO"><正>
customer_admin
</#if><#if authn_info["username"][0]?c_upper_case == "HITACHI_TARO">
customer_admin
</#if>
- テンプレートで属性(顧客)を割り当てる場合